java design pattern (sections 13-19)

catalogue

Interface isolation principle -- object oriented design principle

Definition of interface isolation principle

Advantages of interface isolation principle

Implementation method of interface isolation principle

Dimitri's Law -- object oriented design principle

Definition of Demeter's law

Advantages of Dimitri's law

Implementation of Dimitri's law

Composite Reuse Principle -- object oriented design principle

Definition of composite Reuse Principle

Importance of composite Reuse Principle

Implementation method of synthetic Reuse Principle

Characteristics and classification of creative patterns

Detailed explanation of single case mode (single case design mode)

Definition and characteristics of singleton pattern

Advantages and disadvantages of singleton mode

Application scenario of singleton mode

Structure and implementation of singleton pattern

1. Structure of singleton mode

Application examples of singleton mode

Extension of singleton mode

Detailed explanation of prototype mode (prototype design mode)  

Definition and characteristics of prototype pattern

Structure and implementation of prototype pattern

Application examples of prototype pattern

Application scenario of prototype pattern

Extension of prototype pattern

Interface isolation principle -- object oriented design principle

Object oriented design principles Opening and closing principle,Richter substitution principle,Dependency Inversion Principle and Single responsibility principle In addition, there are interface isolation principles Dimitt's law Synthesis and reuse principles. This section will introduce the interface isolation principle in detail.

Definition of interface isolation principle

The Interface Segregation Principle (ISP) requires programmers to split the bulky interface into smaller and more specific interfaces as far as possible, so that the interface only contains methods of interest to customers.

In 2002, Robert C. Martin defined the "interface isolation principle" as: Clients should not be forced to depend on methods they do not use. The principle also has another definition: The dependency of one class to another one should depend on the smallest possible interface.

The meaning of the above two definitions is to establish a special interface for each class, rather than trying to establish a huge interface for all classes that depend on it to call.

The principle of interface isolation and single responsibility are to improve the cohesion of classes and reduce the coupling between them, reflecting the idea of encapsulation, but they are different:

  • The single responsibility principle focuses on responsibilities, while the interface isolation principle focuses on the isolation of interface dependencies.
  • The single responsibility principle is mainly a constraint class, which aims at the implementation and details of the program; The principle of interface isolation mainly restricts the interface, and mainly aims at the construction of abstraction and the overall framework of the program.

Advantages of interface isolation principle

The interface isolation principle is to restrict the interface and reduce the dependence of classes on the interface. Following the interface isolation principle has the following five advantages.

  1. Decomposing a bulky interface into multiple interfaces with small granularity can prevent the proliferation of external changes and improve the flexibility and maintainability of the system.
  2. Interface isolation improves the cohesion of the system, reduces external interaction and reduces the coupling of the system.
  3. If the granularity of the interface is reasonably defined, the stability of the system can be guaranteed; However, if the definition is too small, it will cause too many interfaces and complicate the design; If the definition is too large, the flexibility will be reduced, and customized services cannot be provided, which will bring unpredictable risks to the overall project.
  4. Using multiple special interfaces can also reflect the hierarchy of objects, because the definition of the general interface can be realized through interface inheritance.
  5. It can reduce code redundancy in project engineering. Many unused methods are usually placed in too large interfaces. When implementing this interface, redundant code is forced to be designed.

Implementation method of interface isolation principle

When applying the interface isolation principle, it should be measured according to the following rules.

  • The interface should be as small as possible, but limited. An interface serves only one sub module or business logic.
  • Customize services for classes that depend on interfaces. Only the methods required by the caller are provided, and the methods not required are shielded.
  • Understand the environment and refuse to follow blindly. Each project or product has selected environmental factors. Different environments lead to different standards for interface splitting, and in-depth understanding of business logic.
  • Improve cohesion and reduce external interaction. Make the interface do the most with the least methods.


The following introduces the application of the interface isolation principle by taking the student achievement management program as an example.

[example 1] student achievement management procedure.

Analysis: the student achievement management program generally includes the functions of inserting achievement, deleting achievement, modifying achievement, calculating total score, calculating average score, printing achievement information, querying achievement information, etc. if it is obviously unreasonable to put all these functions in one interface, the correct way is to put them in three modules: input module, statistics module and printing module, The class diagram is shown in Figure 1.

package principle;

public class ISPtest {
    public static void main(String[] args) {
        InputModule input = StuScoreList.getInputModule();
        CountModule count = StuScoreList.getCountModule();
        PrintModule print = StuScoreList.getPrintModule();
        input.insert();
        count.countTotalScore();
        print.printStuInfo();
        //print.delete();
    }
}

//Input module interface
interface InputModule {
    void insert();

    void delete();

    void modify();
}

//Statistical module interface
interface CountModule {
    void countTotalScore();

    void countAverage();
}

//Print module interface
interface PrintModule {
    void printStuInfo();

    void queryStuInfo();
}

//Implementation class
class StuScoreList implements InputModule, CountModule, PrintModule {
    private StuScoreList() {
    }

    public static InputModule getInputModule() {
        return (InputModule) new StuScoreList();
    }

    public static CountModule getCountModule() {
        return (CountModule) new StuScoreList();
    }

    public static PrintModule getPrintModule() {
        return (PrintModule) new StuScoreList();
    }

    public void insert() {
        System.out.println("Input module insert()Method called!");
    }

    public void delete() {
        System.out.println("Input module delete()Method called!");
    }

    public void modify() {
        System.out.println("Input module modify()Method called!");
    }

    public void countTotalScore() {
        System.out.println("Of statistical module countTotalScore()Method called!");
    }

    public void countAverage() {
        System.out.println("Of statistical module countAverage()Method called!");
    }

    public void printStuInfo() {
        System.out.println("Printing module printStuInfo()Method called!");
    }

    public void queryStuInfo() {
        System.out.println("Printing module queryStuInfo()Method called!");
    }
}

  The running results of the program are as follows:

Input module insert()Method called!
Of statistical module countTotalScore()Method called!
Printing module printStuInfo()Method called!

Dimitri's Law -- object oriented design principle

In the previous sections, the principles of object-oriented design are introduced in detail Opening and closing principle,Richter substitution principle,Dependency Inversion Principle,Single responsibility principle and Interface isolation principle , this section will introduce the Dimitri rule in detail.

Definition of Demeter's law

Law of Demeter (LoD), also known as the Least Knowledge Principle (LKP), originated from a research project called Demeter of Northeast University in 1987. It was proposed by Ian Holland and adopted by Booch, one of the founders of UML It was widely known later because it was mentioned in the classic book the practical programmer.

The definition of Dimitri's law is: Talk only to your immediate friends and not to strangers It means that if two software entities do not need to communicate directly, they should not call each other directly, and the call can be forwarded through a third party. Its purpose is to reduce the coupling between classes and improve the relative independence of modules.

"Friend" in Dimitri's Law refers to the current object itself, the member object of the current object, the object created by the current object, the method parameters of the current object, etc. these objects are associated, aggregated or combined with the current object, and the methods of these objects can be accessed directly.

Advantages of Dimitri's law

Dimitri's law requires to limit the width and depth of communication between software entities. The correct use of Dimitri's law will have the following two advantages.

  1. It reduces the coupling between classes and improves the relative independence of modules.
  2. Because the affinity is reduced, the reusability of classes and the scalability of the system are improved.


However, the excessive use of Dimitri's law will produce a large number of intermediary classes, which will increase the complexity of the system and reduce the communication efficiency between modules. Therefore, it is necessary to weigh repeatedly when using Dimitri's law to ensure high cohesion and low coupling and clear structure of the system.

Implementation of Dimitri's law

According to the definition and characteristics of Demeter's law, it emphasizes the following two points:

  1. From the perspective of dependencies, only the objects that should be relied on.
  2. From the perspective of the dependent, only the methods that should be exposed are exposed.


Therefore, we should pay attention to the following 6 points when using Dimitri's law.

  1. In the division of classes, weakly coupled classes should be created. The weaker the coupling between classes, the more conducive it is to achieve the goal of reusability.
  2. In the design of class structure, the access rights of class members should be reduced as much as possible.
  3. In class design, priority is given to setting a class as an invariant class.
  4. In terms of references to other classes, minimize the number of references to other objects.
  5. Instead of exposing the attribute members of the class, the corresponding accessors (set and get methods) should be provided.
  6. Use Serializable features with caution.


[example 1] examples of the relationship between stars and brokers.

Analysis: because stars devote themselves to art, many daily affairs are handled by brokers, such as meeting with fans, business negotiation with media companies, etc. The brokers here are friends of stars, while fans and media companies are strangers, so it is suitable to use Dimitri's law. Its class diagram is shown in Figure 1.

package principle;

public class LoDtest {
    public static void main(String[] args) {
        Agent agent = new Agent();
        agent.setStar(new Star("Lin Xinru"));
        agent.setFans(new Fans("Fan Han Cheng"));
        agent.setCompany(new Company("China Media Co., Ltd"));
        agent.meeting();
        agent.business();
    }
}

//agent
class Agent {
    private Star myStar;
    private Fans myFans;
    private Company myCompany;

    public void setStar(Star myStar) {
        this.myStar = myStar;
    }

    public void setFans(Fans myFans) {
        this.myFans = myFans;
    }

    public void setCompany(Company myCompany) {
        this.myCompany = myCompany;
    }

    public void meeting() {
        System.out.println(myFans.getName() + "With stars" + myStar.getName() + "We met.");
    }

    public void business() {
        System.out.println(myCompany.getName() + "With stars" + myStar.getName() + "Negotiate business.");
    }
}

//Star
class Star {
    private String name;

    Star(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

//fans
class Fans {
    private String name;

    Fans(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

//Media company
class Company {
    private String name;

    Company(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

The running results of the program are as follows:

Fan Han Cheng met with star Lin Xinru.
China Media Co., Ltd. negotiated business with star Lin Xinru.

Composite Reuse Principle -- object oriented design principle

Composite Reuse Principle is the last of the seven principles of object-oriented design principles, which will be introduced in detail below.

Definition of composite Reuse Principle

Composite Reuse Principle (CRP) is also called Composition/Aggregate Reuse Principle (CARP). It requires that when reusing software, we should first use association relations such as composition or aggregation, and then consider using inheritance relations.

If you want to use inheritance, you must strictly follow the Richter substitution principle. The synthesis Reuse Principle and the Richter substitution principle complement each other, and both are the specific implementation specifications of the opening and closing principle.

Importance of composite Reuse Principle

Generally, class reuse is divided into inheritance reuse and composition reuse. Although inheritance reuse has the advantages of simplicity and easy implementation, it also has the following disadvantages.

  1. Inheritance reuse destroys the encapsulation of classes. Because inheritance will expose the implementation details of the parent class to the child class, and the parent class is transparent to the child class, this reuse is also called "white box" reuse.
  2. The coupling between subclass and parent class is high. Any change in the implementation of the parent class will lead to changes in the implementation of the child class, which is not conducive to class expansion and maintenance.
  3. It limits the flexibility of reuse. The implementation inherited from the parent class is static and has been defined at compile time, so it cannot change at run time.


When using combination or aggregation reuse, the existing object can be incorporated into the new object to become a part of the new object. The new object can call the functions of the existing object. It has the following advantages.

  1. It maintains the encapsulation of classes. Because the internal details of the component object are invisible to the new object, this reuse is also called "black box" reuse.
  2. The coupling between old and new classes is low. This reuse requires less dependence. The only way for new objects to access component objects is through the interface of component objects.
  3. High flexibility of reuse. This reuse can be carried out dynamically at runtime, and new objects can dynamically reference objects of the same type as component objects.

Implementation method of synthetic Reuse Principle

The principle of composite reuse is realized by incorporating the existing objects into the new objects as the member objects of the new objects. The new objects can call the functions of the existing objects to achieve reuse.

Next, take the automobile classification management program as an example to introduce the application of the synthesis Reuse Principle.

[example 1] automobile classification management procedure.

Analysis: according to the "power source", vehicles can be divided into gasoline vehicles, electric vehicles, etc; According to the "color", it can be divided into white cars, black cars and red cars. If these two classifications are considered at the same time, there are many combinations. Figure 1 shows a class diagram of automobile classification realized by inheritance relationship.


As can be seen from Figure 1, the implementation of inheritance relationship will produce many subclasses, and the source code must be modified to add a new "power source" or add a new "color", which violates the opening and closing principle and is obviously undesirable. However, the above problems can be well solved by using composite relationship implementation. The class diagram is shown in Figure 2.

Combined with the contents of the previous sections, we introduced seven design principles, namely, opening and closing principle, Richter substitution principle, dependency inversion principle, single responsibility principle, interface isolation principle, Demeter principle and synthesis Reuse Principle.

These seven design principles are the principles that software design patterns must follow as much as possible and are the basis of design patterns. In the actual development process, it is not necessary to require all codes to follow the design principles, but to comprehensively consider manpower, time, cost and quality, do not deliberately pursue perfection, and follow the design principles in appropriate scenarios. This reflects a balanced trade-off, which can help us design a more elegant code structure.

The emphasis of various principles is different. Next, we summarize the seven principles of software design pattern in one sentence, as shown in the table below.
 

Design principlesOne sentence inductionobjective
Opening and closing principleIt is open to extensions and closed to modificationsReduce new risks caused by maintenance
Dependency Inversion PrincipleThe high level should not rely on the low level, but should be interface oriented programmingIt is more conducive to the upgrading and expansion of code structure
Single responsibility principleA class only does one thing, and the implementation class should be singleEasy to understand and improve the readability of the code
Interface isolation principleAn interface only does one thing, and the interface should be simplified and singleFunctional decoupling, high aggregation and low coupling
Dimitt's lawDon't know what you shouldn't know. A class should keep the least understanding of other objects and reduce the degree of couplingOnly communicate with friends and don't talk to strangers to reduce code bloat
Richter substitution principleDo not destroy the inheritance system. The function of subclass overriding methods should be changed, and the meaning of parent class methods should not be affectedPrevent the spread of inheritance
Synthetic Reuse PrincipleTry to use combination or aggregation relationship to realize code reuse, and use inheritance lessReduce code coupling


In fact, the purpose of these principles is only one: reduce the coupling between objects and increase the reusability, scalability and maintainability of programs.

Memory formula: access plus restrictions, functions should be frugal, dependencies are not allowed, interfaces should be added dynamically, parent classes should be abstract, and extensions should not be changed.

In programming, we should minimize program function and do only one thing for each class. If you add new functions based on similar functions, you should make rational use of inheritance. For the call of multiple methods, you should be able to use the interface, and reasonably set the function and quantity of the interface. Finally, low coupling and high cohesion are achieved between classes.

Characteristics and classification of creative patterns

The main focus of creation mode is "how to create objects?", and its main feature is "separating the creation and use of objects". This can reduce the coupling degree of the system. Users do not need to pay attention to the creation details of objects. The creation of objects is completed by relevant factories. Just like when we go to the mall to buy goods, we don't need to know how the goods are produced, because they are produced by special manufacturers.

The creation mode is divided into the following types.

  • Singleton mode: a class can only generate one instance. This class provides a global access point for external access to the instance. Its extension is the limited multiple instance mode.
  • Prototype mode: take an object as a prototype and clone multiple new instances similar to the prototype by copying it.
  • Factory method pattern: defines an interface for creating products, and subclasses determine what products to produce.
  • Abstract factory pattern: it provides an interface to create a product family, and each subclass can produce a series of related products.
  • Builder mode: decompose a complex object into several relatively simple parts, then create them according to different needs, and finally build the complex object.


The above five creation modes, except Factory method model It belongs to class creation mode, and all the others belong to object creation mode. We will introduce their characteristics, structure and application in detail in the next tutorial.

Detailed explanation of single case mode (single case design mode)

In some systems, in order to save memory resources and ensure the consistency of data content, it is required to create only one instance of some classes, which is the so-called singleton mode.

Definition and characteristics of singleton pattern

Definition of Singleton pattern: a pattern in which a class has only one instance and the class can create the instance itself. For example, only one task manager can be opened in Windows, which can avoid the waste of memory resources caused by opening multiple task manager Windows, or errors such as inconsistent display contents of each window.

In the computer system, there are also the recycle bin of Windows, the file system in the operating system, the thread pool in multithreading, the driver object of the graphics card, the background processing service of the printer, the log object of the application, the connection pool of the database, the counter of the website, the configuration object of the Web application, the dialog box in the application The cache in the system is often designed as a singleton.

The singleton model is also widely used in real life. For example, the company CEO and department manager all belong to the singleton model. In J2EE standard   Servlet Context and ServletContextConfig Spring   The ApplicationContext in the framework application and the connection pool in the database are also singleton modes.

The singleton mode has three features:

  1. A singleton class has only one instance object;
  2. The singleton object must be created by the singleton class itself;
  3. The singleton class provides a global access point for accessing the singleton.

Advantages and disadvantages of singleton mode

Advantages of singleton mode:

  • Singleton mode can ensure that there is only one instance in memory and reduce the memory overhead.
  • Multiple occupation of resources can be avoided.
  • Set global access points in singleton mode to optimize and share resource access.


Disadvantages of singleton mode:

  • The singleton mode generally has no interface and is difficult to expand. If you want to expand, there is no second way except to modify the original code, which violates the opening and closing principle.
  • In concurrent testing, singleton mode is not conducive to code debugging. During debugging, if the code in the singleton is not executed, a new object cannot be simulated.
  • The function code of singleton mode is usually written in a class. If the function design is unreasonable, it is easy to violate the principle of single responsibility.

The singleton pattern looks very simple and easy to implement. Single case mode is a high-frequency interview question in the interview. I hope you can study hard, master the single case mode, improve your core competitiveness, give extra points to the interview and get the Offer smoothly.

Application scenario of singleton mode

about   Java   For example, the singleton pattern ensures that there is only a single instance in a JVM. The application scenarios of singleton mode mainly include the following aspects.

  • For some classes that need to be created frequently, using singleton can reduce the memory pressure of the system and reduce GC.
  • A class only requires the generation of an object, such as the monitor in a class, the ID number of everyone.
  • Some classes occupy more resources when creating instances, or instantiation takes a long time and is often used.
  • When a class needs frequent instantiation and the created objects are frequently destroyed, such as multi-threaded thread pool, network connection pool, etc.
  • Objects that frequently access databases or files.
  • For some control hardware level operations, or from the system point of view, they should be single control logic operations. If there are multiple instances, the system will be completely disordered.
  • When objects need to be shared. Since singleton mode allows only one object to be created, sharing the object can save memory and speed up object access. Such as the configuration object in the Web, the connection pool of the database, etc.

Structure and implementation of singleton pattern

The singleton mode is Design pattern One of the simplest modes in. Generally, the constructors of ordinary classes are public, and external classes can generate multiple instances through "new constructor()". However, if the constructor of a class is made private, the external class cannot call the constructor and cannot generate multiple instances. At this time, the class itself must define a static private instance and provide a static public function to create or obtain the static private instance.

The basic structure and implementation method are analyzed below.

1. Structure of singleton mode

The main roles of singleton mode are as follows.

  • Singleton class: a class that contains an instance and can create the instance itself.
  • Access class: a class that uses a singleton.


Its structure is shown in Figure 1.

public class LazySingleton {
    private static volatile LazySingleton instance = null;    //Ensure that instance is synchronized in all threads

    private LazySingleton() {
    }    //private prevents classes from being instantiated externally

    public static synchronized LazySingleton getInstance() {
        //Add synchronization before getInstance method
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

  Note: if you are writing a multithreaded program, do not delete the keywords volatile and synchronized in the above example code, otherwise there will be a thread unsafe problem. If you do not delete these two keywords, you can ensure thread safety, but you have to synchronize each access, which will affect performance and consume more resources. This is the disadvantage of lazy singleton.

Type 2: starving Han style single case

The feature of this pattern is that once the class is loaded, a singleton is created to ensure that the singleton already exists before calling the getInstance method.

public class HungrySingleton {
    private static final HungrySingleton instance = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return instance;
    }
}


Hungry Chinese singleton has created a static object for the system to use at the same time as the class is created, which will not be changed in the future. Therefore, it is thread safe and can be directly used for multithreading without problems.

Application examples of singleton mode

[example 1] the lazy singleton model is used to simulate the generation of the current presidential object of the United States.

Analysis: in each term of office, there is only one president of the United States, so this example is suitable for implementation in singleton mode. Figure 2 shows the structure diagram of implementation in lazy singleton mode.

public class SingletonLazy {
    public static void main(String[] args) {
        President zt1 = President.getInstance();
        zt1.getName();    //Output the president's name
        President zt2 = President.getInstance();
        zt2.getName();    //Output the president's name
        if (zt1 == zt2) {
            System.out.println("They are the same person!");
        } else {
            System.out.println("They are not the same person!");
        }
    }
}

class President {
    private static volatile President instance = null;    //Ensure that instance is synchronized in all threads

    //private prevents classes from being instantiated externally
    private President() {
        System.out.println("Produce a president!");
    }

    public static synchronized President getInstance() {
        //Add synchronization to getInstance method
        if (instance == null) {
            instance = new President();
        } else {
            System.out.println("There is already a president, can not produce a new president!");
        }
        return instance;
    }

    public void getName() {
        System.out.println("I am the president of the United States: trump.");
    }
}

  The running results of the program are as follows:

Produce a president!
I am the president of the United States: trump.
There is already a president, can not produce a new president!
I am the president of the United States: trump.
They are the same person!


[example 2] simulate the generation of pig Bajie object with hungry Han single case mode.

Analysis: similar to the above example, there is only one pig Bajie, so this example is also suitable for single instance mode. This example shows the image of pig Bajie( Click here to download the pig Bajie picture to be displayed by the program )Therefore, the framework form JFrame component is used. The pig Bajie class here is a singleton class, which can be defined as a subclass of the panel JPanel, which contains labels to save the pig Bajie image. The customer form can obtain the pig Bajie object and display it. Fig. 3 shows a structure diagram of a starving Han style single example.

import java.awt.*;
import javax.swing.*;

public class SingletonEager {
    public static void main(String[] args) {
        JFrame jf = new JFrame("Hungry Han singleton mode test");
        jf.setLayout(new GridLayout(1, 2));
        Container contentPane = jf.getContentPane();
        Bajie obj1 = Bajie.getInstance();
        contentPane.add(obj1);
        Bajie obj2 = Bajie.getInstance();
        contentPane.add(obj2);
        if (obj1 == obj2) {
            System.out.println("They are the same person!");
        } else {
            System.out.println("They are not the same person!");
        }
        jf.pack();
        jf.setVisible(true);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

class Bajie extends JPanel {
    private static Bajie instance = new Bajie();

    private Bajie() {
        JLabel l1 = new JLabel(new ImageIcon("src/Bajie.jpg"));
        this.add(l1);
    }

    public static Bajie getInstance() {
        return instance;
    }
}

  The program running results are shown in Figure 4.

Extension of singleton mode

The singleton mode can be extended to a limited Multitcm mode. This mode can generate a limited number of instances and save them in the ArrayList. Customers can obtain them randomly when they need them. Its structure is shown in Figure 5.

Detailed explanation of prototype mode (prototype design mode)  

In some systems, there is a problem of creating a large number of identical or similar objects. If you use the traditional constructor to create objects, it will be more complex, time-consuming and resource-consuming. It is very efficient to generate objects with the prototype mode, just as it is as simple as the monkey king pulling out the monkey's hair and blowing it gently to create many monkey kings.

Definition and characteristics of prototype pattern

The definition of Prototype pattern is as follows: take an already created instance as the Prototype, and create a new object that is the same or similar to the Prototype by copying the Prototype object. Here, the Prototype instance specifies the kind of object to create. Creating objects in this way is very efficient, and you don't need to know the details of object creation at all. For example, the installation of Windows operating system is usually time-consuming, and replication is much faster. There are many examples of replication in life, which are not listed here one by one.

Advantages of prototype mode:

  • Java   The built-in prototype mode is based on the replication of memory binary stream, and its performance is better than that of directly new an object.
  • You can use deep cloning to save the state of an object, and use prototype mode to copy an object and save its state, which simplifies the process of creating an object for use when needed (for example, restoring to a certain state in History), and can assist in the implementation of undo.

Disadvantages of prototype mode:

  • You need to configure a clone method for each class
  • The clone method is located inside the class. When modifying an existing class, you need to modify the code, which violates the opening and closing principle.
  • When implementing deep cloning, you need to write more complex code, and when there are multiple nested references between objects, in order to implement deep cloning, the classes corresponding to each layer of objects must support deep cloning, which will be troublesome to implement. Therefore, deep cloning and shallow cloning need to be used properly.

Structure and implementation of prototype pattern

Because Java provides the clone() method of the object, it is easy to implement the prototype pattern in Java.

1. Structure of the model

The prototype pattern contains the following main roles.

  1. Abstract prototype class: Specifies the interface that the concrete prototype object must implement.
  2. Concrete prototype class: implement the clone() method of the Abstract prototype class, which is an object that can be copied.
  3. Access class: use the clone() method in the concrete prototype class to copy the new object.


Its structure is shown in Figure 1.

2. Implementation of mode

The cloning of prototype pattern can be divided into shallow cloning and deep cloning.

  • Shallow cloning: create a new object. The properties of the new object are exactly the same as the original object. For non basic type properties, it still points to the memory address of the object pointed to by the original property.
  • Deep clone: when a new object is created, other objects referenced in the attribute will also be cloned and no longer point to the original object address.


The Object class in Java provides the clone() method of shallow cloning. The specific prototype class can realize the shallow cloning of objects as long as it implements the clonable interface, which is an abstract prototype class. Its code is as follows:

//Concrete prototype class
class Realizetype implements Cloneable {
    Realizetype() {
        System.out.println("The specific prototype was created successfully!");
    }

    public Object clone() throws CloneNotSupportedException {
        System.out.println("Specific prototype copied successfully!");
        return (Realizetype) super.clone();
    }
}

//Prototype pattern test class
public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype obj1 = new Realizetype();
        Realizetype obj2 = (Realizetype) obj1.clone();
        System.out.println("obj1==obj2?" + (obj1 == obj2));
    }
}

 
The running results of the program are as follows:

The specific prototype was created successfully!
Specific prototype copied successfully!
obj1==obj2?false

Application examples of prototype pattern

[example 1] copy yourself by simulating "Monkey King" in prototype mode.

Analysis: the monkey king pulls out the monkey's hair and blows it gently to change a lot of Monkey King, which actually uses the prototype model. The monkey king class SunWukong here is a concrete prototype class, while the clonable interface in Java is an abstract prototype class.

Like the pig Bajie example introduced earlier, due to the display of the image of the monkey king( Click here to download the picture of the monkey king to be displayed by the program )Therefore, the monkey king class is defined as a subclass of the panel JPanel, which contains tags to save the monkey king image.

In addition, the clone() method of the clonable interface is rewritten to copy the new monkey king. The access class can copy multiple Monkey King by calling Monkey King's clone() method and display it in the frame form JFrame. Figure 2 shows its structure.

import java.awt.*;
import javax.swing.*;

class SunWukong extends JPanel implements Cloneable {
    private static final long serialVersionUID = 5543049531872119328L;

    public SunWukong() {
        JLabel l1 = new JLabel(new ImageIcon("src/Wukong.jpg"));
        this.add(l1);
    }

    public Object clone() {
        SunWukong w = null;
        try {
            w = (SunWukong) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("Copy Wukong failed!");
        }
        return w;
    }
}

public class ProtoTypeWukong {
    public static void main(String[] args) {
        JFrame jf = new JFrame("Prototype mode test");
        jf.setLayout(new GridLayout(1, 2));
        Container contentPane = jf.getContentPane();
        SunWukong obj1 = new SunWukong();
        contentPane.add(obj1);
        SunWukong obj2 = (SunWukong) obj1.clone();
        contentPane.add(obj2);
        jf.pack();
        jf.setVisible(true);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

  The running results of the program are shown in Figure 3.

 
In addition to generating the same objects, you can also generate similar objects with prototype mode. Please see the following examples.

[example 2] generate the certificate of "three good students" with the prototype mode.

Analysis: the "three good students" certificates of the same school are the same except for the names of the winners. They belong to the replication of similar objects. They can also be created in the prototype mode, and then simply modified. Figure 4 shows the structure of the three good student certificate generator.

public class ProtoTypeCitation {
    public static void main(String[] args) throws CloneNotSupportedException {
        citation obj1 = new citation("Zhang San", "Classmate: excellent performance in the first semester of 2016 academic year, and was rated as three good students.", "shaoguan university ");
        obj1.display();
        citation obj2 = (citation) obj1.clone();
        obj2.setName("Li Si");
        obj2.display();
    }
}

//Certificate of merit
class citation implements Cloneable {
    String name;
    String info;
    String college;

    citation(String name, String info, String college) {
        this.name = name;
        this.info = info;
        this.college = college;
        System.out.println("Certificate created successfully!");
    }

    void setName(String name) {
        this.name = name;
    }

    String getName() {
        return (this.name);
    }

    void display() {
        System.out.println(name + info + college);
    }

    public Object clone() throws CloneNotSupportedException {
        System.out.println("Certificate of award copied successfully!");
        return (citation) super.clone();
    }
}


The running results of the program are as follows:

Certificate created successfully!
Classmate Zhang San: he performed well in the first semester of 2016 academic year and was rated as three good students. shaoguan university 
Certificate of award copied successfully!
Classmate Li Si: he performed well in the first semester of 2016 academic year and was rated as a three good student. shaoguan university 

Application scenario of prototype pattern

The prototype pattern is generally applicable to the following scenarios.

  • Objects are the same or similar, that is, when only several individual attributes are different.
  • The cost of creating objects is large, such as long initialization time, too much CPU, or too much network resources. Resources need to be optimized.
  • Creating an object requires cumbersome data preparation or access rights, and needs to improve performance or security.
  • This kind of object is widely used in the system, and each caller needs to re assign its properties.


stay   Spring   In, prototype patterns are widely used, such as scope='prototype ', JSON.parseObject(), etc.

Extension of prototype pattern

The prototype pattern can be extended to the prototype pattern with prototype manager. It adds a prototype manager PrototypeManager class on the basis of the prototype pattern. This class uses HashMap to save multiple copied prototypes, and the Client class can obtain the copied prototypes through the get(String id) method of the manager. Its structure is shown in Figure 5.

[example 3] use the prototype mode with prototype manager to generate a prototype containing figures such as "circle" and "square", and calculate its area. Analysis: in this example, because there are different graphic classes, such as "circle" and "square", their area calculation methods are different, so they need to be managed by a prototype manager. Figure 6 shows its structure diagram.

import java.util.*;

interface Shape extends Cloneable {
    public Object clone();    //Copy

    public void countArea();    //Calculated area
}

class Circle implements Shape {
    public Object clone() {
        Circle w = null;
        try {
            w = (Circle) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("Copy circle failed!");
        }
        return w;
    }

    public void countArea() {
        int r = 0;
        System.out.print("This is a circle. Please enter the radius of the circle:");
        Scanner input = new Scanner(System.in);
        r = input.nextInt();
        System.out.println("Area of the circle=" + 3.1415 * r * r + "\n");
    }
}

class Square implements Shape {
    public Object clone() {
        Square b = null;
        try {
            b = (Square) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("Copy square failed!");
        }
        return b;
    }

    public void countArea() {
        int a = 0;
        System.out.print("This is a square. Please enter its side length:");
        Scanner input = new Scanner(System.in);
        a = input.nextInt();
        System.out.println("The area of the square=" + a * a + "\n");
    }
}

class ProtoTypeManager {
    private HashMap<String, Shape> ht = new HashMap<String, Shape>();

    public ProtoTypeManager() {
        ht.put("Circle", new Circle());
        ht.put("Square", new Square());
    }

    public void addshape(String key, Shape obj) {
        ht.put(key, obj);
    }

    public Shape getShape(String key) {
        Shape temp = ht.get(key);
        return (Shape) temp.clone();
    }
}

public class ProtoTypeShape {
    public static void main(String[] args) {
        ProtoTypeManager pm = new ProtoTypeManager();
        Shape obj1 = (Circle) pm.getShape("Circle");
        obj1.countArea();
        Shape obj2 = (Shape) pm.getShape("Square");
        obj2.countArea();
    }
}


The operation results are as follows:

This is a circle. Please enter the radius of the circle: 3
 Area of the circle=28.2735

This is a square. Please enter its side length: 3
 The area of the square=9

Today, I'll update it here. I'll see you in the next issue.

Tags: Java Algorithm

Posted on Sat, 25 Sep 2021 13:19:56 -0400 by xSN1PERxEL1TEx