Design Mode - 23 design patterns (rpm)

Transfer: HTTP:. //Blog.csdn NET / zhangerqing have deletion

Design patterns (Design Patterns) 

                             - Elements of Reusable Object-Oriented Software

Design patterns (Design pattern) is set to be repeated use, known to most people, after cataloging, code design experience summary. Use design patterns to reusable code, make the code easier to understand others, to ensure the reliability of the code. There is no doubt, in others in design mode systems are win-win for others, design patterns make code compiled real engineering, design patterns is the cornerstone of software engineering, like a piece of brick stone building of the same. Project rational use of design patterns can be the perfect solution to many problems, in reality each mode has a corresponding principle corresponding Each pattern describes a constantly recurring problem around us, and the core of the problem Cause solution, which is that it can be widely used. Java chapter of the United States Department of [evolution from novice to expert] series of design patterns, we will combine theory and practice to learn the way of this chapter to provide our program enthusiasts, to learn design patterns, do a good software engineer!

A classification, design patterns

Overall, the design patterns into three categories:

Create a schema, a total of five categories: factory method pattern, abstract factory pattern, singleton, the builder pattern, prototype model.

Structural model, a total of seven kinds: adapter mode, decorative mode, proxy mode, the appearance mode, bridge mode, combination mode, Flyweight.

Behavioral patterns, a total of eleven kinds: Strategy pattern, the template method pattern, observer mode, iterator pattern, the responsibility chain mode, command mode, the memo mode state mode, the visitor pattern, intermediary model to explain the mode.

In fact, there are two types: concurrency pattern and thread pool mode. With a picture to describe the whole:

Second, create a schema

1, the factory method model (Factory Method)

Factory Method pattern is divided into three types:

1.1 ordinary factory pattern : that is, to build a factory class, to achieve the same interface classes created instance. First, look at the diagram:

 

For example as follows :( We give an example of sending e-mail and SMS)

First, create common interfaces between the two:

public interface Sender {
    public void Send();
}

Second, create an 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, build factories categories:

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("请输入正确的类型!");
            return null;
        }
    }
}

test:

public class FactoryTest {
    public static void main(String[] args) {
        SendFactory factory = new SendFactory();
        Sender sender = factory.produce("sms");
        sender.Send();
    }
}

Output: this is sms sender!

1.2 plurality mode factory method: a method of improving plant ordinary mode, in the normal mode, the factory method, if the transmission error string, the object can not be created properly, and the plurality of modes to provide a plurality of methods plant factory method, respectively, create objects. relation chart:

 The code to do the above modifications, adaptations, based on the SendFactory line, as follows:

public class SendFactory {
    
    public Sender produceMail(){
        return new MailSender();
    }
    
    public Sender produceSms(){
        return new SmsSender();
    }
}

test:

public class FactoryTest {
    public static void main(String[] args) {
        SendFactory factory = new SendFactory();
        Sender sender = factory.produceMail();
        sender.Send();
    }
}

Output: this is mailsender!

1.3 static factory method pattern: The above multiple factory method pattern set in the static method does not need to create an instance, you can direct calls to.

public class SendFactory {
    
    public static Sender produceMail(){
        return new MailSender();
    }
    
    public static Sender produceSms(){
        return new SmsSender();
    }
}

test:

public class FactoryTest {
    public static void main(String[] args) {    
        Sender sender = SendFactory.produceMail();
        sender.Send();
    }
}

Output: this is mailsender!

Overall, while there have been a large number of those who need to create a product, and have a common interface that can be created by the factory method pattern. In the above three modes, the first if the string passed in error, you can not create objects correctly, and the third in relation to the second, without instantiating the factory class, so, in most cases, we will a third choice - static factory method pattern.

2, Abstract Factory (Abstract Factory)

Factory Method pattern there is a problem, create a class of dependent factory class. That is, if you want to expand the program, you must modify the class factory, which is contrary to the principle of closure. So, from the design point of view, there are some problems, how to solve? To use the abstract factory pattern to create multiple factory class, so once the need to add new features, add new direct factory class on it, no need to modify the code before. Because the abstract factory do not really understand, we look at the pictures, and then the code easier to understand.

interface:

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 factories categories:

public class SendMailFactory implements Provider {
    @Override
    public Sender produce(){
        return new MailSender();
    }
}

public class SendSmsFactory implements Provider{
    @Override
    public Sender produce() {
        return new SmsSender();
    }
}

Then a consumer interfaces:

public interface Provider {
    public Sender produce();
}

test:

public class Test {
    public static void main(String[] args) {
        Provider provider = new SendMailFactory();
        Sender sender = provider.produce();
        sender.Send();
    }
}

In fact, the benefits of this model is that if you now want to add a function: send timely information, you only need to do to achieve a class that implements the interface Sender, while doing a factory class that implements the Provider interface is OK, no need to change existing code. In doing so, develop better.

3, singleton pattern (the Singleton)

Singleton pattern (the Singleton) is a common design pattern. In a Java application, the singleton can guarantee a JVM, only one instance of the object exists. This model has several advantages:

  1. Some class creates more frequently, for some large object, which is a lot of overhead.
  2. Eliminating the new operator, reducing the frequency of use of system memory, reduce stress GC.
  3. Some classes, such as the exchange's core trading engine, control the transaction process, if the class can create multiple words, the system is completely chaotic. (For example, there have been more than a military commander to simultaneously command, will certainly be a mess, so only use single-case model, in order to ensure that the core transaction server independent control of the whole process)

(By rotation Note: If you are interested can refer Deep analysis singleton )

First, we write a simple singleton class:

public  class the Singleton { 
 
    / * holds private static instance, prevent cited herein assignment is null, the aim is to achieve a delay loading * / 
    Private  static the Singleton instance = null ; 
 
    / * private constructor, prevent instantiated * / 
    Private the Singleton () { 
    } 
 
    / * static engineering methods, create an instance * / 
    public  static the Singleton the getInstance () {
         IF (instance == null ) { 
            instance = new new the Singleton (); 
        } 
        return instance; 
    } 
 
    / * If the object is a sequence technology, ensures consistent before and after the object serialization * / 
    public Object readResolve() {
        return instance;
    }
}

This class meet the basic requirements, but, like there is no thread-safe protection class, if we put it in a multithreaded environment, certainly there will be problems, how to solve? We first think of adding synchronized keyword getInstance method, as follows:

public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

However, synchronized keyword is locked object, such usage, the performance will decline, because each call to getInstance (), should be locked object, in fact, only the first created object when you need to lock, then you do not need, so, this place needs to be improved. We changed to the following:

public static Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
    }
    return instance;
} 

Seems to solve the problems mentioned earlier, the synchronized keyword added to the inside, that is to say when the call is not required when locked, only the instance is null, and create objects only need to lock, performance some improvement. However, such a situation, there may be a problem or look at the following scenario: create objects and assignment operations are carried out separately in Java instruction, that instance = new Singleton (); statement is executed in two steps. But the JVM does not guarantee the order of these two operations, which means that there may be a new JVM instance Singleton allocate space, then directly assigned instance member, then go to initialize the Singleton instance. This may be wrong, we have to A, B two threads, for example:

  1. A, B threads into the first determining if a
  2. A first enters the synchronized block, since the instance is null, it performs instance = new Singleton ();
  3. Since the optimization mechanism of the internal JVM, JVM first draw some blank memory allocated to the Singleton instance, and assigned to the instance members (note that at this time does not begin to initialize the JVM instance), then left the A synchronized block.
  4. B enters the synchronized block, since this time instance is not null, it immediately left the synchronized block and returns the result to the program that called the method.
  5. At this point B threads plan to use the Singleton instance, only to find that it has not been initialized, so the error occurred.

So the program is still possible errors, in fact, during the operation of the program is very complicated, from this point we can see, especially in the writing process more difficult in a multi-threaded environment, challenging. We further optimized the program:

    private static class SingletonFactory {
        private static Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonFactory.instance;
    }

The fact is, singleton inner class implemented to maintain a single embodiment, the internal mechanism can be guaranteed when a JVM class is loaded, the loading process of this class is the thread mutually exclusive . So that when we first call the getInstance, JVM can help us ensure that instance is created only once, and will ensure that the memory assigned to the instance initialized, so we do not worry about the above issues. Meanwhile, the method will also use mutual exclusion mechanism at the time of the first call, this would resolve the problem of low performance. So we do a perfect summary of the Singleton pattern:

public  class the Singleton { 
 
    / * private constructor, prevent instantiated * / 
    Private the Singleton () { 
    } 
 
    / * As used herein, a single embodiment to maintain internal class * / 
    Private  static  class SingletonFactory {
         Private  static the Singleton instance = new new the Singleton () ; 
    } 
 
    / * Get instance * / 
    public  static the Singleton the getInstance () {
         return SingletonFactory.instance; 
    } 
 
    / * If the object is of a sequence can be ensured consistent before and after the object serialization * / 
    public Object readResolve () {
         return getInstance();
    }
}

In fact it perfect, not necessarily, if an exception is thrown in the constructor, the instance will never be created, will be wrong. So, something is not quite perfect, we can only according to the actual situation, choose the most suitable implementation scenarios. It was this realization: because we only need to be synchronized, so long as the creation and getInstance () to create a separate class at the time, to create a separate add synchronized keyword, it is also possible:

public class SingletonTest {
    private static SingletonTest instance = null;
    private SingletonTest() {
    }
    private static synchronized void syncInit() {
        if (instance == null) {
            instance = new SingletonTest();
        }
    }
    public static SingletonTest getInstance() {
        if (instance == null) {
            syncInit();
        }
        return instance;
    }
}

For performance, the entire program created once instance, so the performance would not be affected.

Through the study of singleton tells us:

1, singleton simple to understand, but it still has some specific implementation difficulty.

2, synchronized keyword lock is the object, when in use, be sure to use (attention to the need to use locking objects and procedures, may sometimes not the whole object and the whole process needs to lock) at the right place. 

Here, Singleton has basically been finished, at the end, I suddenly thought of another problem, is to use a static class method to achieve the effect of singletons, also feasible, both here what is the difference? 

First, a static class can not implement the interface. (From the perspective of the class said they could, but that would undermine the static, because the interface has a static method does not allow modifications, even if achieved is non-static)

Second, a single embodiment may be delayed initialized, typically static class initialization is first loaded. The reason why the delay in loading, because some classes relatively large, lazy loading so help improve performance.

Again, singleton class can be inherited, his methods can be overridden. But the internal static class methods are static, and can not be overwritten.

Finally, singleton class more flexible, after all, from the realization of just a regular Java class, as long as the basic needs of a single case, you can achieve some other functions inside arbitrary, but not static class.

From the above these generalizations, the basic difference between the two can be seen, but, on the other hand, the final realization of the Singleton pattern above us, inside is to use a static class to implement, so the two are very the association, but we consider the issue of the level difference in terminology. Combination of the two ideas, to create a perfect solution, using an array as HashMap + linked list to achieve the same, in fact, are so many things in life, to deal with a single issue in different ways, there are always advantages and disadvantages, best approach is to combine the advantages of each method in order to best solve the problem!

4, builder mode (Builder)

Factory class model offers is to create a single class model, and builders clock is to manage a variety of products together, to create composite objects. The so-called composite objects refers to a class have different properties, in fact, the builder pattern is in front of the abstract factory pattern and final Test combine get.

Also as before, a Sender interface implementation class MailSender and two SmsSender. Finally, the builder category as follows:

public class Builder {
    
    private List<Sender> list = new ArrayList<Sender>();
    
    public void produceMailSender(int count){
        for(int i=0; i<count; i++){
            list.add(new MailSender());
        }
    }
    
    public void produceSmsSender(int count){
        for(int i=0; i<count; i++){
            list.add(new SmsSender());
        }
    }
}

test:

public class Test {
    public static void main(String[] args) {
        Builder builder = new Builder();
        builder.produceMailSender(10);
    }
}

From this point we see that the builder pattern to a lot of functionality into a class, this class can create more complex stuff. So the difference is the factory pattern: the factory model concern is to create a single product, but the builder pattern is created in line with the focus on an object . Therefore, the factory pattern is selected or the builder pattern, according to the actual situation.

5, prototype model (the Prototype)

Although the prototype model is to create a type of mode, but nothing to do with the factory model. You can see from the name, the idea is to model an object as a prototype, its copy, clone, and generates a new object similar to the original object. This summary will be copied by the object, to explain. In Java, an object is copied by clone () to achieve, to create a prototype class:

public class Prototype implements Cloneable {
 
    public Object clone() throws CloneNotSupportedException {
        Prototype proto = (Prototype) super.clone();
        return proto;
    }
}

Very simple, a prototype class, only the interface Cloneable, the clone method override the need to achieve, where the clone method can be changed to any name, because Cloneable interface is an empty interface, you can define any class that implements the method name, such as cloneA or cloneB because the focus here is on super.clone () this sentence, super.clone () call is the Object clone () method, while in the Object class, clone () is a native of how to achieve specific, I will in another article, about the interpretation of the Java native method call, no longer go into details here. Here, I will combine shallow copy and deep copy the object is, first of all need to understand the depth of the object, the concept of shallow copy:

Shallow copy: After an object is copied, the basic data types of variables will be re-created, and reference types, or the original point of object points.

Deep Copy: copy after an object, whether there is a reference type is the basic data types, are re-created. Simply put, deep copy was full and complete copy, but a pale copy is not complete.

Here, write an example of the depth of the copy:

public class Prototype implements Cloneable, Serializable {
 
    private static final long serialVersionUID = 1L;
    private String string;
 
    private SerializableObject obj;
 
    /* 浅复制 */
    public Object clone() throws CloneNotSupportedException {
        Prototype proto = (Prototype) super.clone();
        return proto;
    }
 
    /* 深复制 */
    public Object deepClone() throws IOException, ClassNotFoundException {
 
        / * The binary stream output current object * / 
        ByteArrayOutputStream BOS = new new ; ByteArrayOutputStream () 
        the ObjectOutputStream OOS = new new the ObjectOutputStream (BOS); 
        oos.writeObject ( the this ); 
 
        / * new object reads the binary stream generated * / 
        A ByteArrayInputStream BIS = new new A ByteArrayInputStream (bos.toByteArray ()); 
        the ObjectInputStream OIS = new new the ObjectInputStream (BIS);
         return ois.readObject (); 
    } 
 
    / * omitted herein the setter getters * / 
 
} 
 
class SerializableObject implements Serializable {
    private static final long serialVersionUID = 1L;
}

To achieve deep copy, we need a form of a stream read binary input current object, and then write the binary data corresponding to the object.

Guess you like

Origin www.cnblogs.com/helios-fz/p/11895926.html