Design patterns are a set of repeated use, most people know, through the classification of purpose, code design experience Summary. Design patterns are used in order to reuse code, make code easier for others to understand, and ensure code reliability. There is no doubt that design patterns in others in the system are more win, design patterns so that the code is really engineering, design pattern is the cornerstone of software engineering, like a block of bricks and stones in the building. The rational use of design patterns in the project can perfectly solve many problems, each pattern now has a corresponding principle in place, each of which describes a recurring problem around us and the core solution to the problem, which is why it is widely used.
I. Classification of design Patterns
Overall, the design pattern is divided into three main categories:
The creation pattern, altogether five kinds: The factory method pattern, the abstract factory pattern, the single case pattern, the builder pattern, the prototype pattern.
Structure mode, a total of seven kinds: Adapter mode, adorner mode, agent mode, appearance mode, bridging mode, combination mode, enjoy meta mode.
There are 11 types of behavioral Patterns: Policy mode, template method pattern, observer mode, iterative sub mode, responsibility chain mode, Command mode, Memo mode, state mode, visitor mode, mediator mode, interpreter mode.
There are two other types of concurrency: concurrent and thread-pool mode. Use a picture to describe the whole:
Second, Java 23 design pattern
Starting from this piece, we introduce the concept of 23 design Patterns in Java, the application scenarios and so on, and combine their characteristics and design patterns of the principles of analysis.
1. Factory mode (Factory method)
The factory method model is divided into three kinds:
11, the Common factory model is to establish a factory class, the implementation of the same interface for some classes to create an instance. First look at the diagram:
Examples are as follows: (we give an example of sending emails and texting)
First, create a common interface between the two: public interface Sender {public void Send (); }
Second, create the implementation class: public class mailsender implements sender { @Override public void send () { system.out.println ("this is mailsender!"); } } public class smssender implements Sender { @Override public void send () { System.out.println ("this is sms sender!"); } }
Finally, plant Category: public class sendfactory { public Sender produce (string type) { if ("Mail". Equals (Type)) { return new mailsender (); } else if ("SMS". Equals (Type)) { return new smssender (); } else { system.out.println ("Please enter the correct type!"); return null; } } }
Let's test this: public class Factorytest {public static void main (string[] args) {Sendfactory factory = new S Endfactory (); Sender Sender = factory.produce ("SMS"); Sender. Send (); } }
Output: This is SMS sender!
22, a number of factory method models , is the general factory method model improvement, in the ordinary factory method mode, if the string passed in error, you can not create the correct object, and multiple factory method mode is to provide multiple factory methods, create objects. Diagram:
:: __ihacklog_remote_image_autodown_block__::2
Modify the above code, change the Sendfactory class on the line, as follows: public class sendfactory { public Sender producemail () { return new MailSender (); } public sender producesms () { Return new smssender (); } }
The test classes are as follows: public class Factorytest {public static void main (string[] args) {Sendfactory factory = new Se Ndfactory (); Sender Sender = Factory.producemail (); Sender. Send (); } }
Output: This is mailsender!
33. Static Factory Method Mode, the methods in the above multiple factory method modes are set to static and can be called directly without creating an instance. public class sendfactory { public static sender producemail () { return new mailsender (); } public static sender producesms () { return new smssender (); } } public class factorytest { public static void main (String[] args) { sender sender = sendfactory.producemail () ; sender. Send (); &nBsp } }
Output: This is mailsender!
In general, the factory pattern is appropriate: whenever a large number of products need to be created and have a common interface, they can be created through the factory method pattern. In the above three modes, the first if the passed-in string is incorrect, the object cannot be created correctly, and the third is relative to the second, no instance chemical plant class is needed, so, in most cases, we will choose the third-static factory method pattern.
2. Abstract Factory Model (abstracts Factory)
Factory method Pattern There is a problem is that the creation of classes rely on the factory class, that is, if you want to expand the program, you must modify the factory class, which violates the closure principle, so from the design point of view, there are certain problems, how to solve. Use the abstract factory pattern to create multiple factory classes so that once you need to add new functionality, you can add new factory classes directly, without needing to modify the previous code. Because the abstract factory is not very understanding, we first look at the map, and then the code, it is easier to understand.
See Example: public interface Sender {public void Send (); }
Two implementation classes: public class mailsender implements sender { @Override public void send () { system.out.println ("this is mailsender!"); } } public class smssender implements Sender { @Override public void send () { System.out.println ("this is sms sender!"); } }
Two factory classes: public class Sendmailfactory implements Provider {@Override public Sender produce () { return new MailSender (); } public class Sendsmsfactory implements provider{@Override public Sender Produce () {Retu RN new Smssender (); } }
In providing an interface: public interface Provider {public Sender produce (); }
Test class: public class Test {public static void main (string[] args) {Provider Provider = new Sendmailfacto Ry (); Sender Sender = Provider.produce (); Sender. Send (); } }
In fact, the advantage of this model is that if you now want to add a function: Send timely information, you need to do a realization class, realize sender interface, at the same time do a factory class, realize provider interface, OK, no need to change ready-made code. In doing so, the development is better.
3. Single case mode (Singleton)
A single Example object (Singleton) is a common design pattern. In Java applications, a singleton object can guarantee that only one instance of the object exists in a JVM. There are several benefits to this pattern:
1, some classes to create more frequent, for some large objects, this is a large amount of system overhead.
2, eliminates the new operator, reduces the system memory usage frequency, reduces the GC pressure.
3, some classes, such as the core trading engine of the exchange, control the transaction flow, if the class can create multiple words, the system is completely chaotic. (for example, a military presence of several commanders at the same time command, will certainly mess), so only the use of single case mode, to ensure that the core trading server independent control of the entire process.
First we write a simple single case class: public class singleton { /* Hold a private static instance to prevent reference, the assignment is null here to implement deferred loading */ private static singleton instance = null; /* Private construction methods to prevent instantiation */ private singleton () { } /* Static Engineering method, creating an instance */ public static singleton getinstance () { if (instance == null) { instance = new singleton (); } return Instance; &nbSp } /* If the object is used for serialization, you can guarantee that the object remains consistent before and after serialization */ public object readresolve () { return instance; } }
This class can meet the basic requirements, but, like this thread-safe class, if we put it into a multithreaded environment, there will certainly be problems, how to solve. We will first think of the getinstance method plus synchronized keyword, as follows: Public static synchronized singleton getinstance ( ) { if (instance == null) { instance = new singleton (); } return instance; }
However, the Synchronized keyword locks This object, such usage, will be reduced in performance, because each call getinstance (), the object is locked, in fact, only the first time you create the object need to lock, and then do not need, so, This place needs to be improved. Let's change this to the following: Public static singleton getinstance () { if (instance == null) { synchronized (instance) { if (Instance == null) { instance = new singleton (); } } } &nBsp return instance; }
It seems to solve the problem mentioned before, add the Synchronized keyword in the internal, that is, when the call is not required to lock, only in instance null, and create objects when the need to add locks, performance has a certain degree of improvement. However, there may be a problem with this scenario: the creation of objects and assignment operations in a Java directive is done separately, i.e. instance = new Singleton (), and the statement is executed in two steps. But the JVM does not guarantee the sequencing of these two operations, which means it is possible for the JVM to allocate space for the new singleton instance and then assign the value directly to the instance member before initializing the singleton instance. This could be an error, we take a, b two threads for example:
A>a and B Threads entered the first if judgment at the same time
B>a first enters the synchronized block, because instance is null, so it executes instance = new Singleton ();
C> because of the internal optimization mechanism of the JVM, the JVM first drew some blank memory allocated to the singleton instance and assigned it to the instance member (note that the JVM did not begin initializing this instance), then a left the synchronized block.
D>b enters the synchronized block, and since instance is not NULL at this time, it immediately leaves the synchronized block and returns the result to the program that invoked the method.
E> at this point the B thread intended to use the singleton instance, but found that it was not initialized, so the error occurred.
So the program is still likely to be wrong, in fact, the program is running in the process is very complex, from this we can see, especially in the write multithreaded environment of the program more difficult, challenging. We further optimize the program: private static class singletonfactory{ private static singleton instance = new singleton (); } public static singleton getinstance () { return SingletonFactory.instance; }
The reality is that a single case pattern uses an internal class to maintain a single instance, and the mechanism inside the JVM ensures that when a class is loaded, the loading process of the class is thread-exclusive. So when we first call getinstance, the JVM can help us make sure that the instance is created once and that the memory assigned to instance is initialized so that we don't have to worry about the problem above. At the same time, this method will only use the mutex mechanism at the first call, which solves the low performance problem. This allows us to briefly summarize a perfect single case pattern: public class singleton { /* Private construction methods to prevent instantiation */ private singleton () { } /* Use an internal class to maintain the single example */ private static class SingletonFactory { private static singleton instance = new singleton (); } /* Get instance */ public static singleton getinstance () { return singletonfactory.instance; } /* If the object is used for serialization, you can ensure that the object remains consistent before and after serialization */ public object readresolve () { Return getinstance (); } }
The
Actually says it's perfect, not necessarily, if you throw an exception in the constructor, the instance will never be created, and there will be an error. So, the perfect thing is not, we can only according to the actual situation, choose the most suitable for their own application scenario implementation. Others do this: since we only need to synchronize when we create the class, it's OK to separate the creation and getinstance () and create the Synchronized keyword individually: public class singletontest { private static singletontest instanc