Create pattern
Simple factory
Select different parameters to generate different products. switch () can be used for parameter selection
public class FoodFactory {
public static Food makeFood(String name) {
if (name.equals("noodle")) {
Food noodle = new LanZhouNoodle();
noodle.addSpicy("more");
return noodle;
} else if (name.equals("chicken")) {
Food chicken = new HuangMenChicken();
chicken.addCondiment("potato");
return chicken;
} else {
return null;
}
}
}
Factory mode
(two or more factories are required) the client generates corresponding factory instances according to different parameters, and the factory generates unused products
public interface FoodFactory {
Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {
@Override
public Food makeFood(String name) {
if (name.equals("A")) {
return new ChineseFoodA();
} else if (name.equals("B")) {
return new ChineseFoodB();
} else {
return null;
}
}
}
public class AmericanFoodFactory implements FoodFactory {
@Override
public Food makeFood(String name) {
if (name.equals("A")) {
return new AmericanFoodA();
} else if (name.equals("B")) {
return new AmericanFoodB();
} else {
return null;
}
}
}
public class APP {
public static void main(String[] args) {
// Select a specific factory first
FoodFactory factory = new ChineseFoodFactory();
// The factory in the first step generates specific objects, and different factories create different objects
Food food = factory.makeFood("A");
}
}
Abstract factory
When it comes to product families, it is necessary to introduce the abstract factory pattern.
A classic example is building a computer. Let's not introduce the abstract factory pattern and see how to implement it.
Because the computer is composed of many components, we abstract the CPU and the motherboard, and then the CPU is produced by CPUFactory, and the motherboard is produced by MainBoardFactory
Production, and then we combine the CPU and the motherboard together, as shown in the following figure:
factory-1
The client call at this time is as follows:
// Get Intel CPU
CPUFactory cpuFactory = new IntelCPUFactory();
CPU cpu = intelCPUFactory.makeCPU();
// Get AMD motherboard
MainBoardFactory mainBoardFactory = new AmdMainBoardFactory();
MainBoard mainBoard = mainBoardFactory.make();
// Assembling CPU and motherboard
Computer computer = new Computer(cpu, mainBoard);
Look at the CPU factory and motherboard factory separately. They are the factory mode we mentioned earlier. This method is also easy to expand, because if you want to add a hard disk to the computer, you only need to add one
HardDiskFactory and the corresponding implementation are sufficient, and there is no need to modify the existing factory.
However, there is a problem with this method, that is, if the CPU made by Intel and the motherboard made by AMD are not compatible
, then the code is error prone, because the client does not know that they are incompatible, and there will be random combinations by mistake.
The following is the concept of product family, which represents a set of accessories that make up a product:
abstract-factory-2
When it comes to the problem of this product family, it needs to be supported by the abstract factory pattern. We no longer define CPU s
Factories, mainboard factories, hard disk factories, display screen factories, etc. we directly define computer factories. Each computer factory is responsible for producing all equipment, which can ensure that there is no compatibility problem.
abstract-factory-3
At this time, the client does not need to be selected separately
CPU manufacturers, motherboard manufacturers, hard disk manufacturers, etc. directly choose a brand factory. The brand factory will be responsible for producing all things, and can ensure that they are compatible and available.
public static void main(String[] args) {
// The first step is to select a "big factory"
ComputerFactory cf = new AmdFactory();
// Make CPU from this big factory
CPU cpu = cf.makeCPU();
// Make motherboards from this big factory
MainBoard board = cf.makeMainBoard();
// Make hard drives from this big factory
HardDisk hardDisk = cf.makeHardDisk();
// Assemble the CPU, motherboard and hard disk from the same factory
Computer result = new Computer(cpu, board, hardDisk);
}
Of course, the problem of abstract factories is also obvious. For example, if we want to add a display, we need to modify all factories and add the method of manufacturing displays to all factories. It's a little against the law
The design principle of closing for modification and opening for extension.
Singleton mode
The hungry man mode is the simplest:
public class Singleton {
// First, block new Singleton()
private Singleton() {};
// Creating a private static instance means that this class will be created when it is first used
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
// Write a static method. What we want to say here is that if we just want to call singleton getDate(...),
// Originally, I didn't want to generate a Singleton instance, but I can't help it. It has been generated
public static Date getDate(String mode) {return new Date();}
}
Many people can tell the disadvantages of the hungry man mode, but I think this is rarely encountered in the production process: you define a singleton class without its instance, but you plug one or more static methods you will use into this class.
The most error prone mode:
public class Singleton {
// First, block the road of new Singleton()
private Singleton() {}
// Compared with the hungry man mode, there is no need to instantiate it first. Note the volatile here, which is necessary
private static volatile Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
// Lock
synchronized (Singleton.class) {
// This judgment is also necessary, otherwise there will be concurrency problems
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Double check refers to checking whether instance is null twice.
volatile is needed here. I hope it can attract the attention of readers.
Many people don't know how to write. They just add synchronized to the getInstance() method signature. That's enough. The performance is too poor.
Nested classes are the most classic. Let's use them in the future:
public class Singleton3 {
private Singleton3() {}
// It mainly uses nested classes to access the static properties and static methods of external classes
private static class Holder {
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance() {
return Holder.instance;
}
}
Note that many people will describe this nested class as a static inner class. Strictly speaking, inner classes and nested classes are different, and they can access different permissions of external classes.
Finally, let's talk about enumeration. Enumeration is very special. It initializes all instances when the class is loaded, and the JVM ensures that they will not be instantiated again, so it is inherently singleton.
Although we seldom see enumerations to implement singletons, enumerations are used in many places in the source code of RxJava.
Builder pattern
The classes of xbuilder that we often meet are usually the product of the builder pattern. In fact, there are many variants of the builder mode, but for the client, we usually use the same mode:
Food food = new FoodBuilder().a().b().c().build();
Food food = Food.builder().a().b().c().build();
The routine is to create a new Builder first, then call a bunch of methods in a chain, and finally call the build() method again, and we have the objects we need.
package com.wxx.pattern;
class User {
// Here are the properties of "a pile"
private String name;
private String password;
private String nickName;
private int age;
private User(String name, String password, String nickName, int age) {
this.name = name;
this.password = password;
this.nickName = nickName;
this.age = age;
}
public static UserBuilder build(){
return new UserBuilder();
}
public static class UserBuilder{
// As like as two peas, User is a bunch of attributes.
private String name;
private String password;
private String nickName;
private int age;
private UserBuilder() {
}
// The chain call sets the value of each attribute and returns this, that is, UserBuilder
public UserBuilder name(String name) {
this.name = name;
return this;
}
public UserBuilder password(String password) {
this.password = password;
return this;
}
public UserBuilder nickName(String nickName) {
this.nickName = nickName;
return this;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
// The build() method is responsible for "copying" the properties set in UserBuilder to User
// Of course, you can do some checking before "copying"
public User build(){
if(name == null || password == null){
throw new RuntimeException("User name and password cannot be empty");
}
if (age <= 0 || age >= 150) {
throw new RuntimeException("Illegal age");
}
// You can also assign the function of "default value"
if (nickName == null) {
nickName = name;
}
return new User(name, password, nickName, age);
}
}
}
//Call in client
public static void main(String[] args) {
User d = User.build().name("foo").password("1244").age(25).build();
}
Prototype mode
The prototype pattern is very simple: there is a prototype instance, and a new instance is generated based on this prototype instance, that is, "clone".
There is a clone() method in the Object class, which is used to generate a new Object. Of course, if we want to call this method, java requires our class to * * implement it first
Clonable interface * *. This interface does not define any method, but if it does not do so, it will be thrown when clone()
CloneNotSupportedException exception.
protected native Object clone() throws CloneNotSupportedException;
java Cloning is a shallow cloning. When an object reference is encountered, the cloned object and the reference in the original object will point to the same object. The usual way to implement deep cloning is to serialize the object and then deserialize it.
Summary of creative mode
- Simple factory mode is the simplest;
- The factory mode adds the dimension of selecting factories on the basis of the simple factory mode. The first step is to select an appropriate factory;
- Abstract factory pattern has the concept of product family. If each product has compatibility problems, it is necessary to use abstract factory pattern.
- Not to mention the singleton mode. In order to ensure that the same object is used globally, on the one hand, it is for security and on the other hand, it is to save resources;
- The builder pattern deals specifically with the type with many attributes in order to make the code more beautiful;
- The prototype pattern is the least used. It is enough to understand the knowledge related to the clone() method in the Object class.
Structural model
Creative pattern is used to create an object, while structural pattern aims to achieve decoupling by changing the code structure, making our code easier to expand and decouple.
proxy pattern
Since it's an agent
, it is necessary to hide the real implementation from the client, and the agent is responsible for all requests of the client. Of course, the agent is just an agent. It will not complete the actual business logic, but a layer of skin. However, for the client, it must be the real implementation required by the client.
public interface FoodService {
Food makeChicken();
Food makeNoodle();
}
public class FoodServiceImpl implements FoodService {
public Food makeChicken() {
Food f = new Chicken()
f.setChicken("1kg");
f.setSpicy("1g");
f.setSalt("3g");
return f;
}
public Food makeNoodle() {
Food f = new Noodle();
f.setNoodle("500g");
f.setSalt("5g");
return f;
}
}
// The agent needs to be "like" a real implementation class, so it needs to implement FoodService
public class FoodServiceProxy implements FoodService {
// There must be a real implementation class inside. Of course, it can also be injected through construction methods
private FoodService foodService = new FoodServiceImpl();
public Food makeChicken() {
System.out.println("We're about to start making chicken");
// If we define this sentence as the core code, then the core code is made by the real implementation class,
// Agents just do "insignificant" things before and after the core code
Food food = foodService.makeChicken();
System.out.println("The chicken is done. Add some pepper"); // enhance
food.addCondiment("pepper");
return food;
}
public Food makeNoodle() {
System.out.println("Prepare Ramen~");
Food food = foodService.makeNoodle();
System.out.println("The production is finished")
return food;
}
}
For client calls, note that we need to instantiate the interface with a proxy:
// Proxy classes are used here to instantiate
FoodService foodService = new FoodServiceProxy();
foodService.makeChicken();
proxy
The agent mode is simply "method packaging" or "method enhancement". In aspect oriented programming, it is actually the process of dynamic agent. Like Spring
In, we don't define proxy classes ourselves, but Spring will help us define proxies dynamically, and then define us in @ Before, @ After, @ Around
The code logic in is dynamically added to the agent.
When it comes to dynamic proxy, it can be expanded to say that there are two ways to implement dynamic proxy in Spring. One is if our class defines interfaces, such as UserService interface and
UserServiceImpl implementation, then the dynamic proxy of JDK is adopted. Interested readers can go to Java lang.reflect. Proxy
Class source code; The other is that we do not define an interface ourselves. Spring will use CGLIB for dynamic proxy. It is a jar package with good performance.
Adapter mode
Generally speaking, there are three adapter modes: default adapter mode, object adapter mode and class adapter mode. Don't rush to distinguish these. Let's look at the examples first.
Default adapter mode
First, let's take a look at the simplest adapter pattern, the default adapter pattern.
We use the FileAlterationListener in the Apache commons IO package
As an example, this interface defines many methods for monitoring files or folders. Once the corresponding operation occurs, the corresponding methods will be triggered.
public interface FileAlterationListener {
void onStart(final FileAlterationObserver observer);
void onDirectoryCreate(final File directory);
void onDirectoryChange(final File directory);
void onDirectoryDelete(final File directory);
void onFileCreate(final File file);
void onFileChange(final File file);
void onFileDelete(final File file);
void onStop(final FileAlterationObserver observer);
}
A big problem with this interface is that there are too many abstract methods. If we want to use this interface, it means that we need to implement each abstract method. If we just want to monitor the creation and of files in folders
File deletion event, but we still have to implement all methods. Obviously, this is not what we want.
Therefore, we need the following adapter to implement the above interface, but all methods are empty methods
In this way, we can instead define our own class to inherit the following class.
public class FileAlterationListenerAdaptor implements FileAlterationListener {
public void onStart(final FileAlterationObserver observer) {
}
public void onDirectoryCreate(final File directory) {
}
public void onDirectoryChange(final File directory) {
}
public void onDirectoryDelete(final File directory) {
}
public void onFileCreate(final File file) {
}
public void onFileChange(final File file) {
}
public void onFileDelete(final File file) {
}
public void onStop(final FileAlterationObserver observer) {
}
}
For example, we can define the following classes. We only need to implement the methods we want to implement:
public class FileMonitor extends FileAlterationListenerAdaptor {
public void onFileCreate(final File file) {
// File creation
doSomething();
}
public void onFileDelete(final File file) {
// File deletion
doSomething();
}
}
Of course, the above is only one of the adapter modes and the simplest one. There is no need to say more. Next, let's introduce the "orthodox" adapter mode.
Object Adapter Pattern
Let's watch Head First
As an example in design pattern, I modified it slightly to see how to adapt chicken to duck, so that chicken can also be used as duck. Because we don't have an appropriate implementation class for this interface, we need an adapter.
public interface Duck {
public void quack(); // The quack of a duck
public void fly(); // fly
}
public interface Cock {
public void gobble(); // The cooing of a chicken
public void fly(); // fly
}
public class WildCock implements Cock {
public void gobble() {
System.out.println("Coo");
}
public void fly() {
System.out.println("Chickens can fly, too");
}
}
The duck interface has two methods, fly() and square (). If chicken Cock wants to impersonate duck, the fly() method is ready-made, but chicken can't croak like duck. There is no square ()
method. Adaptation is needed at this time:
// There is no doubt that first of all, this adapter must need implements Duck to be used as a duck
public class CockAdapter implements Duck {
Cock cock;
// A chicken instance is required in the construction method. This class is used to adapt the chicken to a duck
public CockAdapter(Cock cock) {
this.cock = cock;
}
// Method for realizing duck quack
@Override
public void quack() {
// Inside is actually the cooing of a chicken
cock.gobble();
}
@Override
public void fly() {
cock.fly();
}
}
The client call is simple:
public static void main(String[] args) {
// There is a pheasant
Cock wildCock = new WildCock();
// Successfully adapted pheasant to duck
Duck duck = new CockAdapter(wildCock);
...
}
Here, you will know what the adapter mode is. It's just that we need a duck, but we only have a chicken. At this time, we need to define an adapter to act as a duck, but the methods in the adapter are still implemented by the chicken.
adapter-1
Interpretation: I only have SomeThing in my hand now, but I want to use the Target object. What should I do?
- Inject the object SomeThing I own into the adapter, that is, the adapted object;
- The purpose can be achieved by implementing the target method with your own method in the adapter;
Class adapter mode
Cut the crap and go straight to the figure above:
adapter-1
It should be easy for you to understand this figure. Through the inherited method, the adapter automatically obtains most of the required methods. At this time, the client is easier to use, directly ` Target t = new
SomeAdapter();` That's it.
Adapter mode summary
- Similarities and differences between class adaptation and object adaptation
One adopts inheritance and the other adopts combination;
Class adaptation belongs to static implementation, object adaptation belongs to dynamic implementation of composition, and object adaptation needs to instantiate one more object.
Generally speaking, object adaptation is used more.
- Similarities and differences between adapter mode and agent mode
Comparing these two modes is actually comparing the object adapter mode and the proxy mode. In terms of code structure, they are very similar, and both need an instance of a specific implementation class. However, their purposes are different. What the agent mode does is to enhance the vitality of the original method; The adapter does the adaptation work to provide "packaging the chicken into a duck and then use it as a duck", and there is no inheritance relationship between the chicken and the duck.
adapter-5
Decoration mode
First, let's look at a simple diagram. When looking at this diagram, we can understand the following hierarchy:
decorator-1
Let's talk about the starting point of decoration mode. As can be seen from the figure, the interface Component actually has ConcreteComponentA and
ConcreteComponentB has two implementation classes. However, if we want to enhance these two implementation classes, we can adopt decoration mode and use specific decorators to implement them
Decorate the implementation class to achieve the purpose of enhancement.
Recently, "happy lemon" has become popular in the street. We divide the drinks of happy lemon into three categories: black tea, green tea and coffee. On the basis of these three categories, many flavors have been added, such as kumquat lemon black tea, kumquat lemon pearl green tea, mango black tea, mango pearl black tea, roasted pearl black tea, roasted pearl mango green tea, coconut germ coffee Caramel, cocoa, coffee, etc. each store has a long menu, but look carefully. In fact, there are few raw materials, but they can match many combinations. If customers need, they can also make many drinks that do not appear in the menu.
In this example, black tea, green tea and coffee are the most basic drinks, while others such as kumquat, lemon, mango, pearl, coconut and caramel are used for decoration. Of course, we can develop these classes like stores: lemon blacktea, lemon greentea, mango blacktea, mango lemon greentea However, we soon found that this kind of work must not work, which will lead us to combine all the possibilities, and what if the guest needs to add double lemon to the black tea? What about three lemons?
Stop talking nonsense and code.
First, define the beverage abstract base class:
public abstract class Beverage {
// Return description
public abstract String getDescription();
// Return price
public abstract double cost();
}
Then there are three basic beverage implementation categories, black tea, green tea and coffee:
public class BlackTea extends Beverage {
public String getDescription() {
return "black tea";
}
public double cost() {
return 10;
}
}
public class GreenTea extends Beverage {
public String getDescription() {
return "Green Tea";
}
public double cost() {
return 11;
}
}
...// Coffee omission
Define seasoning, that is, the base class of decorator. This class must inherit from Beverage:
// Seasoning
public abstract class Condiment extends Beverage {
}
Then let's define lemon, mango and other specific condiments. They belong to decorators. There is no doubt that these condiments must inherit the Condiment class:
public class Lemon extends Condiment {
private Beverage bevarage;
// It is very important to introduce specific drinks, such as black tea or green tea without decoration,
// Of course, it can also be introduced into the decorated mango green tea, which can be made into mango lemon green tea
public Lemon(Beverage bevarage) {
this.bevarage = bevarage;
}
public String getDescription() {
// decorate
return bevarage.getDescription() + ", Add lemon";
}
public double cost() {
// decorate
return beverage.cost() + 2; // It costs 2 yuan with lemon
}
}
public class Mango extends Condiment {
private Beverage bevarage;
public Mango(Beverage bevarage) {
this.bevarage = bevarage;
}
public String getDescription() {
return bevarage.getDescription() + ", Add mango";
}
public double cost() {
return beverage.cost() + 3; // It costs 3 yuan to add mango
}
}
...// Add a class to each seasoning
Look at the client call:
public static void main(String[] args) {
// First, we need a basic drink, black tea, green tea or coffee
Beverage beverage = new GreenTea();
// Start decorating
beverage = new Lemon(beverage); // Add a lemon first
beverage = new Mongo(beverage); // Add another mango
System.out.println(beverage.getDescription() + " Price:¥" + beverage.cost());
//"Green tea with lemon and mango price: ¥ 16"
}
If we need mango pearl double lemon black tea:
Beverage beverage = new Mongo(new Pearl(new Lemon(new Lemon(new BlackTea()))));
Isn't it abnormal?
It may be clearer to look at the following figure:
decorator-2
By now, everyone should have known the decoration mode.
Facade mode
Facade Pattern (also known as Facade Pattern) is used in many source codes, such as slf4j
It can be understood as the application of facade mode. This is a simple design pattern. Let's talk about it directly in the code.
First, we define an interface:
public interface Shape {
void draw();
}
Define several implementation classes:
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
Client call:
public static void main(String[] args) {
// Draw a circle
Shape circle = new Circle();
circle.draw();
// draw a rectangle
Shape rectangle = new Rectangle();
rectangle.draw();
}
Let's define a facade first:
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
/**
* The following defines a bunch of methods, and the specific methods that should be called are determined by this facade */
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
Let's see how the client calls:
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
// Client calls are now clearer
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
The advantages of facade mode are obvious. The client no longer needs to pay attention to which implementation class should be used during instantiation. It can directly call the methods provided by the facade, because the method name of the methods provided by the facade class is already very friendly to the client.
summary
- The proxy mode is enhanced
- The adapter pattern is to wrap a chicken into a duck, which is used to adapt the interface
- The decoration mode can be seen from the name, which is suitable for the scenes of decoration or enhancement
- The advantage of facade mode is that the client does not need to care about the instantiation process, just call the required methods
Behavioral model
Behavioral patterns focus on the interaction between various classes, and divide responsibilities clearly, making our code clearer.
Strategy mode
The policy pattern is too common, so it is introduced at the beginning. It's relatively simple. I don't talk nonsense. Just say things in code.
The following design scenario is that we need to draw a figure. The optional strategy is to draw with a red pen, a green pen, or a blue pen.
First, define a policy interface:
public interface Strategy {
public void draw(int radius, int x, int y);
}
Then we define several specific strategies:
public class RedPen implements Strategy {
@Override
public void draw(int radius, int x, int y) {
System.out.println("Draw with red strokes, radius:" + radius + ", x:" + x + ", y:" + y);
}
}
public class GreenPen implements Strategy {
@Override
public void draw(int radius, int x, int y) {
System.out.println("Draw with green strokes, radius:" + radius + ", x:" + x + ", y:" + y);
}
}
public class BluePen implements Strategy {
@Override
public void draw(int radius, int x, int y) {
System.out.println("Draw with blue strokes, radius:" + radius + ", x:" + x + ", y:" + y);
}
}
Classes using policies:
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeDraw(int radius, int x, int y){
return strategy.draw(radius, x, y);
}
}
Put it on a picture so that everyone can see it clearly:
strategy-1
Observer mode
The observer model can't be simpler for us. There are no more than two operations. Observers subscribe to topics they care about and notify observers of data changes.
First, you need to define topics. Each topic needs to hold a reference to the observer list to notify each observer when the data changes:
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
// The data has changed. Notify the observers
notifyAllObservers();
}
// Registered observer
public void attach(Observer observer) {
observers.add(observer);
}
// Inform the observers
public void notifyAllObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
Define the observer interface:
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
In fact, if there is only one observer class, the interface does not need to be defined. However, in normal scenarios, since the observer mode is used, we just hope that when an event comes out, there will be multiple different classes that need to process corresponding information. For example, in the event of successful order modification, we want the class sending SMS to be notified, the class sending email to be notified, and the class processing logistics information to be notified.
Let's define several specific observer classes:
public class BinaryObserver extends Observer {
// Subscribe to topics in construction methods
public BinaryObserver(Subject subject) {
this.subject = subject;
// In general, you must be careful when publishing this in the construction method
this.subject.attach(this);
}
// This method is called by the topic class when the data changes
@Override
public void update() {
String result = Integer.toBinaryString(subject.getState());
System.out.println("The subscribed data changes, and the new data is processed into binary values:" + result);
}
}
public class HexaObserver extends Observer {
public HexaObserver(Subject subject) {
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
String result = Integer.toHexString(subject.getState()).toUpperCase();
System.out.println("The subscription data changes, and the new data processing is hexadecimal. The value is:" + result);
}
}
The client is also very simple to use:
public static void main(String[] args) {
// Define a topic first
Subject subject1 = new Subject();
// Define observer
new BinaryObserver(subject1);
new HexaObserver(subject1);
// Simulate data changes, at which time the observers' update method will be called
subject.setState(11);
}
output:
The subscribed data changes, and the new data is processed into binary value: 1011
The subscription data changes, and the new data processing is hexadecimal. The value is: B