Study Notes for Design Patterns

6 types of relationships between classes

Before learning design patterns, you need 6 relationships between classes, namely generalization, implementation, dependency, association, aggregation, and combination.

generalization relationship

The generalization relationship is a special case of the dependency relationship, which is the inheritance between two classes, which is the generalization relationship

achieve relationship

The implementation relationship refers to the implementation of the interface. A class implements an interface, which is called implementation.

dependencies

As long as each other is used between two classes, it is called a dependency relationship, which can be expressed as:

  1. A class is a member variable of another class
  2. A class is the return value of a method in another class
  3. One class is a member variable in another class
  4. A class is an argument to a method in another class
  5. One class is a local variable in another class

connection relation

The association relationship is the connection between classes, with one-way relationship and two-way relationship

aggregation relationship

The aggregation relationship refers to the relationship between the whole and the part. The whole and the part can be separated from each other, which is a special case of the association relationship.

combination relationship

The combination relationship refers to the relationship between the whole and the part. The whole and the part cannot be separated from each other, and it is also a special case of the association relationship.

Principles of Design Patterns

Before learning design patterns, there are 6 principles of design patterns that all design patterns need to abide by, namely: single responsibility principle, interface isolation principle, dependency inversion principle, opening and closing principle, Liskov substitution principle, Dimiter's law (least-know principle)

Single Responsibility Principle

Simply put, a single responsibility means that each class or interface only completes one function, so that the original code will not be modified when it is expanded later, and only specific functions need to be added again.

Interface Isolation Principle

When there are many methods in the interface implemented by the subclass, but so many methods are not used in the subclass, so rewriting all the methods in the interface will cause a lot of redundant methods, so the methods in the interface need to be Split into smaller interfaces

Dependency Inversion Principle

The core idea of ​​the dependency inversion principle is interface-oriented programming, and the three ways of dependency transfer are:

  1. interface passing
  2. Constructor pass
  3. setter method passing

Open and close principle

Very abstract, the core idea is to open for extension and close for modification

Liskov Substitution Principle

The Liskov substitution principle is to reduce the degree of coupling. Once there is an inheritance relationship between classes, the degree of coupling will increase. Therefore, when you want to use the method of the parent class and need to extend the functions of the parent class, you can not use it Inheritance method, using the dependency relationship between classes, such as changing the original parent class into a member variable of the subclass, can realize the expansion of functions

Demeter principle

Also known as the principle of least knowledge, it communicates with direct friends. It is said that a class that appears in a class as a member variable, method parameter, or return value of a method is called a friend, and a class that appears in a local variable is not a friend.

23 design patterns

singleton pattern

That is, only one instantiated object can be created in the entire project, so the constructor is required to be privatized, not all program calls can be instantiated, and an external method is also provided to call the only instantiated object

The singleton pattern of the hungry man pattern

As the name implies, the hungry man mode is to create objects regardless of whether you use them or not, for your use, divided into two categories

  1. Hungry mode of static variables, modifying instantiated objects into variables
package com.njupt.single;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/08/19:15
 * @Description:饿汉模式,不管你要不要,都创造出来等你用
 */
public class Hungry {
    
    
    public static void main(String[] args) {
    
    

        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();
        //结果为true说明是同一个对象。
        System.out.println(singleton1==singleton2);

    }
}
//采用静态变量的方式实现饿汉模式
/*
* 优点:在类加载是就完成了实例化,避免了线程同步问题
* 缺点:在类加载是创建出实例化对象,如果没有使用会造成内存的浪费
* */
class Singleton{
    
    
    private static Singleton singleton=new Singleton();
    private Singleton(){
    
    }

    public static Singleton getSingleton(){
    
    
        return singleton;
    }
}
  1. Singleton pattern written in static code block
package com.njupt.single;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/08/19:15
 * @Description:饿汉模式,不管你要不要,都创造出来等你用
 */
public class Hungry {
    
    
    public static void main(String[] args) {
    
    

        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();
        //结果为true说明是同一个对象。
        System.out.println(singleton1==singleton2);
    }
}
//采用静态变量的方式实现饿汉模式
/*
* 优点:在类加载是就完成了实例化,避免了线程同步问题
* 缺点:在类加载是创建出实例化对象,如果没有使用会造成内存的浪费
* */

class Singleton{
    
    
    private static Singleton singleton;
    private Singleton(){
    
    
    }
    static{
    
    singleton=new Singleton();}
    public static Singleton getSingleton(){
    
    
        return singleton;
    }
}

The singleton pattern of the lazy pattern

Think about when to call the method, and when to create the only instantiated object for the caller to use

  1. thread-unsafe lazy mode
package com.njupt.single;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/08/19:01
 * @Description:
 */
public class Lazy {
    
    
    public static void main(String[] args) {
    
    
        Single single = Single.getSingle();
        Single single1 = Single.getSingle();
        System.out.println(single==single1);
    }
}

/*优点:什么时候使用,什么时候才开始创建实例化对象
* 缺点:线程不安全的懒加载,当多个线程使用时,会造成线程安全问题
* */
class Single{
    
    
    private Single(){
    
    
    }
    private static Single single;

    public static Single getSingle(){
    
    
        if(single==null){
    
    
            single=new Single();
        }
        return single;
    }
}
  1. The simplest thread-safe lazy style, but the efficiency is too low.
package com.njupt.single;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/08/19:01
 * @Description:
 */
public class Lazy {
    
    
    public static void main(String[] args) {
    
    
        Single single = Single.getSingle();
        Single single1 = Single.getSingle();
        System.out.println(single==single1);
    }
}

/*优点:什么时候使用,什么时候才开始创建实例化对象,并且是线程安全的
* 缺点:synchronized同步代码块锁的粒度太大,性能较差效率低
* */
class Single{
    
    
    private Single(){
    
    
    }
    private static Single single;

    public static synchronized Single getSingle(){
    
    
        if(single==null){
    
    
            single=new Single();
        }
        return single;
    }
}
  1. double check lock
package com.njupt.single;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/08/19:01
 * @Description:
 */
public class Lazy {
    
    
    public static void main(String[] args) {
    
    
        Single single = Single.getSingle();
        Single single1 = Single.getSingle();
        System.out.println(single==single1);
    }
}

/*优点:什么时候使用,什么时候才开始创建实例化对象,并且是线程安全的
*推荐使用。。。
* */
class Single{
    
    
    private Single(){
    
    
    }
    //volatile关键字禁止指令重排,因为在创建对象时有三步
    /*
    * 1.分配内存
    * 2.初始化对象
    * 3将分配的内存指向初始化对象
    * 
    * 不加volatile会出现的问题
    * 如果两个线程同时进入了同步代码块,当第一个线程抢到锁然后结束之后,
    * 此时可能会先执行1.3两步,没有初始化对象,也就是此时single可能还为null,当第二个线程进入锁后
    * 判断single仍然为空,此时会在创建一个对象,就不满足单例模式的要求了,因此需要volatile关键字来禁止指令重排。
    *
    * */
    private static volatile Single single;
    public static  Single getSingle(){
    
    
        if(single==null){
    
    
            synchronized (Single.class){
    
    
                if(single==null){
    
    
                    single=new Single();
                }
            }
        }
        return single;
    }
}
  1. Lazy loading of static inner classes
    takes advantage of the characteristics of static inner classes:
    1. When the external class is loaded, its static internal class will not be loaded immediately
    2. When calling the method, the static inner class will not be loaded until the variables of the static inner class are used
package com.njupt.single;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/08/21:13
 * @Description:利用静态内部类来实现懒汉模式的单例
 */
public class StaticInnerClass {
    
    
    public static void main(String[] args) {
    
    

        SingleLi singe = SingleLi.getSinge();
        SingleLi singe2 = SingleLi.getSinge();
        System.out.println(singe==singe2);
    }
}
//静态内部类
class SingleLi{
    
    
    //构造方法
    private SingleLi(){
    
    }
    //静态内部类
    private static class InnerSingle{
    
    
        private static SingleLi singleLi=new SingleLi();
    }
    public static SingleLi getSinge(){
    
    
        return InnerSingle.singleLi;
    }
}

Using enumeration to implement singleton pattern

Simple Factory Pattern

The simple factory pattern is a creational pattern, which is a kind of factory pattern. The simple factory pattern is an instance of which product class is created by a factory. The simple factory pattern is the easiest to use pattern in the factory pattern family.
The core idea is to define a class that creates objects, and this class encapsulates the behavior of instantiating objects.
In software development, when we use a large number of objects to create a certain type or a certain type or a certain batch of objects, we will use the factory pattern.

package com.njupt.simpleFactory;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/09/17:24
 * @Description:简单工厂先出现一个抽象的父类,利用多态模式实现简单的工厂模式
 */

//先建立一个抽象的类,让其他的类来继承
public abstract class Operation {
    
    
    public abstract void doMath(int i,int j);
}
class Add extends Operation{
    
    

    @Override
    public void doMath(int i, int j) {
    
    
        System.out.println("相加之后的结果为:"+(i+j));
    }
}
class Sub extends Operation{
    
    

    @Override
    public void doMath(int i, int j) {
    
    
        System.out.println("相减之后的结果:"+(i-j));
    }
}
class Multiple extends Operation{
    
    

    @Override
    public void doMath(int i, int j) {
    
    
        System.out.println("两数相乘之后:"+(i*j));
    }
}
class Div extends Operation{
    
    

    @Override
    public void doMath(int i, int j) {
    
    
        System.out.println("两数相除之后:"+(i/j));
    }
}
//简单工厂,开始处理客户端传入的数据进行处理
class Factory{
    
    

    public static void startMath(int i,int j,String sym){
    
    
        Operation operation;
        if(sym.equals("+")){
    
    
            operation=new Add();
            operation.doMath(i,j);
        }else if(sym.equals("-")){
    
    
            operation=new Sub();
            operation.doMath(i,j);
        }else if(sym.equals("*")){
    
    
            operation=new Multiple();
            operation.doMath(i,j);
        }else if(sym.equals("/")){
    
    
            operation=new Div();
            operation.doMath(i,j);
        }else {
    
    
            System.out.println("输入的符号有误!");
        }
    }
}

client test code

package com.njupt.simpleFactory;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/09/17:43
 * @Description:
 */
public class OperationTest {
    
    
    public static void main(String[] args) {
    
    
        Factory.startMath(3,4,"+");
        Factory.startMath(4,3,"-");
        Factory.startMath(3,4,"*");
        Factory.startMath(4,2,"/");
    }
}

result:

相加之后的结果为:7
相减之后的结果:1
两数相乘之后:12
两数相除之后:2

Process finished with exit code 0 

factory method pattern

abstract factory pattern

prototype pattern

Prototype mode refers to: use prototype instances to create object types, and create new objects by copying these prototypes. Mao becomes like other monkeys.
The working principle is: pass a prototype object to the object to be created, and create an identical object by requesting the prototype objects to copy themselves, that is, object.clone().

Benefit: If the original object changes, other cloned objects will change accordingly, no need to modify the code.
Disadvantages: You need to write a clone method for each class, which is not difficult for the original class, but when you want to modify the cloned class, you need to modify the original class, which is to modify the source code, which violates the ocp principle.

You must implement the Cloneable interface to clone

package com.njupt.prtoTypeMode;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/09/19:44
 * @Description:原型模式
 */
public class Monkey implements Cloneable{
    
    
    private String name;
    private String color;
    private String weapon;
    private int age;

    public Monkey() {
    
    
    }

    public Monkey(String name, String color, String weapon, int age) {
    
    
        super();
        this.name = name;
        this.color = color;
        this.weapon = weapon;
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Monkey{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", weapon='" + weapon + '\'' +
                ", age=" + age +
                '}';
    }

    //原型模式要重写clone方法
    @Override
    protected Object clone()  {
    
    
        Monkey monkey=null;
        try {
    
    
          monkey= (Monkey) super.clone();
        } catch (Exception e) {
    
    
            System.out.println(e.getMessage());
        }
        return monkey;
    }
}

When configuring the scope of the bean tag in xml in the spring framework, the prototype mode will be used: prototype. At this time, the instantiated object can be set to the prototype mode. When there are new attributes, it will be the same as the original class information, but Not a class, because it is not a singleton pattern.

Shallow copy and deep copy of prototyping pattern

  1. Shallow copy
    Shallow copy: If the basic data type is copied during the clone process, value transfer will be performed. If the copy is a reference data type, reference (memory address) transfer will be performed, that is, the reference value of the member ( Memory address) is copied to the new object. For example, if Monkey King's son attribute is also a monkey attribute, when cloning in prototype mode, the memory address transfer (reference transfer) is used for the reference data type.
public class Monkey implements Cloneable{
    
    
    private String name;
    private String color;
    private String weapon;
    private int age;
    //当加入一个引用数据类型时:
    public static Monkey son;

Test Results:

public class ProtoTest {
    
    
    public static void main(String[] args) {
    
    
        Monkey monkey=new Monkey("孙悟空","黄色","金箍棒",25);
        monkey.son=new Monkey("孙小猴","黄色","小棍",2);
        Monkey monkey1 = (Monkey) monkey.clone();
        Monkey monkey2 = (Monkey) monkey.clone();
        Monkey monkey3 = (Monkey) monkey.clone();
        System.out.println(monkey+"引用数据类型的哈希值"+monkey.son.hashCode());
        System.out.println(monkey1+"引用数据类型的哈希值"+monkey1.son.hashCode());
        System.out.println(monkey2+"引用数据类型的哈希值"+monkey2.son.hashCode());
        System.out.println(monkey3+"引用数据类型的哈希值"+monkey3.son.hashCode());
    }
}

Monkey{
    
    name='孙悟空', color='黄色', weapon='金箍棒', age=25}引用数据类型的哈希值764977973
Monkey{
    
    name='孙悟空', color='黄色', weapon='金箍棒', age=25}引用数据类型的哈希值764977973
Monkey{
    
    name='孙悟空', color='黄色', weapon='金箍棒', age=25}引用数据类型的哈希值764977973
Monkey{
    
    name='孙悟空', color='黄色', weapon='金箍棒', age=25}引用数据类型的哈希值764977973

Process finished with exit code 0

Conclusion: It can be seen that when cloning in the prototype mode, the basic data type is assigned directly, and the data of the reference data type is passed by reference (memory address).

That is, shallow copy is implemented by default using the clone() method

2. Deep copy
Deep copy is: for the basic data type to copy the value, for the reference data type, to apply for storage space, and copy the object referenced by each reference data type member variable, and copy the entire object. Deep copy
implementation
a. Rewrite the clone method to achieve deep copy

package com.njupt.prtoTypeMode;

import java.io.Serializable;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/09/20:48
 * @Description:孙悟空的引用数据类型的妻子
 */
public class Fox implements Cloneable, Serializable {
    
    
    private String name;
    private int age;

    public Fox() {
    
    
    }

    public Fox(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Fox{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    //默认的拷贝方式是对基本数据类型进行值传递
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }
}

Sun Wukong class information

package com.njupt.prtoTypeMode;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/09/19:44
 * @Description:深克隆的演示
 */
public class Monkey implements Cloneable{
    
    
    private String name;
    private String color;
    private String weapon;
    private int age;
    //假设猴子有一个妻子
    public Fox wife;
    public Monkey son;

    public Monkey() {
    
    
    }

    public Monkey(String name, String color, String weapon, int age) {
    
    
        super();
        this.name = name;
        this.color = color;
        this.weapon = weapon;
        this.age = age;

    }

    @Override
    public String toString() {
    
    
        return "Monkey{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", weapon='" + weapon + '\'' +
                ", age=" + age +
                '}';
    }

    //原型模式要重写clone方法
    @Override
    protected Object clone()  {
    
    
    //先对此类中的基本数据类型进行克隆,值传递
        Monkey monkey=null;

        try {
    
    
          monkey= (Monkey) super.clone();
          //对应用类型的属性进行单独处理
          monkey.wife=(Fox) wife.clone();
        } catch (Exception e) {
    
    
            System.out.println(e.getMessage());
        }
        return monkey;
    }
}

test code

package com.njupt.prtoTypeMode;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/09/20:52
 * @Description:
 */
public class DeepCloneTest {
    
    
    public static void main(String[] args) {
    
    
        Monkey monkey = new Monkey("monkey", "yellow", "bang", 25);
        monkey.wife=new Fox("狐狸",24);
        System.out.println(monkey+"深克隆之前的引用数据类型地址"+monkey.wife.hashCode());
        
        Monkey m2= (Monkey)monkey.clone();
        System.out.println(m2+"深克隆之后的引用数据类型地址"+m2.wife.hashCode());
    }
}

Test result: It is found that the address of the reference data type wife has changed, indicating that a deep clone has been carried out

Monkey{
    
    name='monkey', color='yellow', weapon='bang', age=25}深克隆之前的引用数据类型地址381259350
Monkey{
    
    name='monkey', color='yellow', weapon='bang', age=25}深克隆之后的引用数据类型地址824318946

Process finished with exit code 0

b. Realize deep copy through object serialization
Utilize the characteristics of serialization: save the reference data type.
You can serialize the original class first, and then deserialize it to realize the deep copy of the reference data type

//将此方法加在monkey类中。
public Object deepClone(){
    
    
        //先创建流对象
        ByteArrayOutputStream bos=null;
        ObjectOutputStream oos=null;
        ByteArrayInputStream bis=null;
        ObjectInputStream ois=null;
        try {
    
    
            //序列化
            bos=new ByteArrayOutputStream();
            oos=new ObjectOutputStream(bos);

            //把当前对象以对象流的方式输出
            oos.writeObject(this);

            //反序列化
            bis=new ByteArrayInputStream(bos.toByteArray());
            ois=new ObjectInputStream(bis);
            Monkey monkey = (Monkey) ois.readObject();
            return monkey;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return null;
        } finally {
    
    
            try {
    
    
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }

test code

public class DeepCloneTest {
    
    
    public static void main(String[] args) {
    
    
        Monkey monkey = new Monkey("monkey", "yellow", "bang", 25);
        monkey.wife=new Fox("狐狸",24);
        System.out.println(monkey+"深克隆之前的引用数据类型地址"+monkey.wife.hashCode());
        /*System.out.println(monkey+"深克隆之前的引用数据类型地址"+monkey.wife.hashCode());
        Monkey m2= (Monkey)monkey.clone();
        System.out.println(m2+"深克隆之后的引用数据类型地址"+m2.wife.hashCode());*/
        //第二种,直接进行序列化进行深克隆
        Monkey m2 = (Monkey) monkey.deepClone();
        System.out.println(m2+"深克隆之后的引用数据类型地址"+m2.wife.hashCode());
    }
}

Result: deep cloning is also achieved

Monkey{
    
    name='monkey', color='yellow', weapon='bang', age=25}深克隆之前的引用数据类型地址381259350
Monkey{
    
    name='monkey', color='yellow', weapon='bang', age=25}深克隆之后的引用数据类型地址693632176

Process finished with exit code 0

builder mode

The builder pattern, also known as the generator pattern, is an object construction pattern that abstracts the complex object creation process. Different implementation methods of this abstraction process can construct objects with different properties.
4 roles in builder mode
insert image description here

  1. Product (product role): a specific product object
  2. Builder (abstract creator): create an interface/abstract class specified by each component of a Product object
  3. ConcreatBuilder (concrete creator): implement an abstract interface or abstract class, responsible for building and implementing specific part functions
  4. Director: Construct an object of the Bulider interface. It is mainly used to create a complex object. It has two functions. One is to isolate the production object of the user and the object, and the other is to control the production process of the product object.

Take building a house as an example:
a. The role of the product is the house, and the house is regarded as an object, which means it has different attributes

public class House {
    
    
    private String base;
    private String wall;
    private String roof;}

b. The abstract creator is the steps of creating a house. All houses need three steps: laying foundations, building walls, roofing, turning into abstract classes, and writing abstract methods for rewriting different styles of houses

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/10/12:03
 * @Description:建造者模式
 */
public abstract class BuildModel {
    
    
    //将与房子视为组合关系。
    House house=new House();
    abstract void buildBase();
    abstract void buildWall();
    abstract void buildRoof();
    public House build(){
    
    
        return house;
    }
}

c. Specific creators: Create different ways of building houses for different house types, inherit abstract methods, and implement interfaces.
For example, to build an ordinary house

package com.njupt.simpleFactory.buildModel;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/10/12:50
 * @Description:
 */
public class NomalHouse extends BuildModel {
    
    
    @Override
    void buildBase() {
    
    
        System.out.println("建造普通方子的地基2米");
    }

    @Override
    void buildWall() {
    
    
        System.out.println("建造普通房子的墙3米");
    }

    @Override
    void buildRoof() {
    
    
        System.out.println("建造普通房子的屋顶小型");
    }
}

like building a villa

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/10/13:46
 * @Description:
 */
public class VillaHouse extends BuildModel {
    
    
    @Override
    void buildBase() {
    
    
        System.out.println("别墅的地基3米");
    }

    @Override
    void buildWall() {
    
    
        System.out.println("别墅的墙5米");
    }

    @Override
    void buildRoof() {
    
    
        System.out.println("别墅的房顶大");

    }
}

d,. The commander can be regarded as the contractor. When the customer finds the contractor, tell him what method to build, and he will create a house according to the demand

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/10/12:53
 * @Description:
 */
public class Boss {
    
    
//属性是针对整个抽象方法,这样可以更加灵活,关系是聚合
    private BuildModel buildModel;

    public Boss(BuildModel buildModel) {
    
    
        this.buildModel = buildModel;
    }

    public House creat(){
    
    
        //建造的具体过程也应该交给包工头去建造
        buildModel.buildBase();
        buildModel.buildWall();
        buildModel.buildRoof();
        //建造好之后就可以返回建造之后的结果
        return buildModel.build();
    }
}

Finally, when the client comes to build a house, he only needs to find the contractor and tell him what style of house he wants.

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/10/10/12:53
 * @Description:
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        //通过构造器传入要盖多大的房子
        Boss boss = new Boss(new NomalHouse());
        //创建之后的结果返回给客户
        House creat = boss.creat();


        //再次建造一个别墅
        Boss boss1=new Boss(new VillaHouse());
        //创建好之后,将别墅返回给客户
        House villa = boss1.creat();
    }
}

Precautions:
The creator mode is generally suitable for creating products that have more in common and have similar components. For example, building a house requires steps such as laying the foundation, building walls, and capping the roof. It is more suitable for the builder mode. Between products If the difference is very large, it is not suitable to use the builder pattern.
The difference between the abstract factory pattern and the builder pattern:
the abstract factory pattern realizes the creation of a product family, and a product family is a series of products. Product Portfolio with Different Ferre Dimensions

The abstract factory pattern does not need to know the construction process, only cares about which factory the product is produced by, while the builder pattern requires the production of products according to the specified blueprint. The main purpose is to assemble parts to produce a new product.

adapter pattern

The function is to fuse the originally incompatible interfaces together, which can be divided into three categories according to the way of conversion into compatibility.

class adapter

Usage scenario: the original class cannot be used, and an adapter class is needed to briefly use it. The original class is called: source class, the adapter class is called Adapter class, and the converted class is called target class dst class. Adapter mode refers to: Adapter
class
through Inherit the src class and implement the dst class interface to complete the adaptation of src–dst.
The limitation of the class adapter: because the original class is to be used, the original src class must be inherited, but because java is a single inheritance mechanism, the dst class must be implemented with an interface, that is, the adapter class must inherit the src class to implement dst Class interface, which can complete the adaptation of src–dst . But inheritance is a disadvantage, but it is precisely because of the inheritance of the original class that the method of the src class can be rewritten according to requirements, which increases the flexibility of the Adapter.

object adapter

The idea of ​​the object adapter is the same as that of the class adapter. Knowledge modifies the Adapter class. Instead of inheriting the src class, the src class is aggregated into the Adapter class to implement the dst interface, and the src-dst adaptation can also be completed.

Solved the problem that the Adapter class adapter must inherit the src class, replaced the inheritance relationship with the association relationship, made the cost lower, and did not require dst to be an interface

interface adapter mode

Usage scenario: When you do not need to implement all the default methods provided by the interface, you can use the interface adapter pattern , which is to create an abstract class first, implement the interface, and then provide a default implementation method for each method in the interface, and then abstract the class You can selectively override the required methods of the parent class for rewriting.

bridge mode

The bridge mode refers to: placing the implementation abstraction in two different class levels, so that the two levels can change the structure independently, and it is a structural design pattern. The main feature is: separate the abstraction layer from the implementation layer, so that the independence of each part can be maintained and the expansion of their functions can be dealt with.
Schematic illustration of the bridge mode
insert image description here:
The Client class is the caller of the bridge mode.
The abstract class Abstraction: maintains the Implementor (including its implementation class). The two are aggregation relationships. Abstraction is the bridge class. Implementor is the interface class
of the behavior implementation class .
Abstract classes are aggregate relationships.
For example, use the bridge mode to solve the problem of mobile phone operation: if you want to add an upright mobile phone, it is more convenient to follow the bridge mode. First, the
insert image description herebrand of the mobile phone is regarded as an interface, which abstracts the functions that all brand mobile phones should have. Apple Huawei and other brands implement interfaces

public interface Brand {
    
    
    public void music();
    public void play();
    public void video();
}

public class Apple implements Brand {
    
    
    @Override
    public void music() {
    
    
        System.out.println("苹果手机听音乐");
    }

    @Override
    public void play() {
    
    
        System.out.println("苹果手机玩游戏");
    }

    @Override
    public void video() {
    
    
        System.out.println("苹果手机看视频");
    }
}

public class Huawei implements Brand {
    
    
    @Override
    public void music() {
    
    
        System.out.println("华为手机听音乐");
    }

    @Override
    public void play() {
    
    
        System.out.println("华为手机玩游戏");
    }

    @Override
    public void video() {
    
    
        System.out.println("华为手机看视频");
    }
}

Then define the mobile phone class as an abstract class, which aggregates the brand interface Brand of the mobile phone, and passes the value through the construction method, so that different brands can be instantiated for different mobile phone brands

public abstract class Phone {
    
    
    Brand brand;
    public Phone(Brand brand){
    
    
        this.brand=brand;
    }
    public void play(){
    
    
        brand.play();
    }
    public void video(){
    
    
        brand.video();
    }
    public void music(){
    
    
        brand.music();
    }
}

Different styles of mobile phones inherit abstract classes, and rewrite the specific functions of the corresponding mobile phones when implementing functions

//折叠手机的具体功能
public class FoldPhone extends Phone {
    
    
    public FoldPhone(Brand brand) {
    
    
        super(brand);
    }
    public void play(){
    
    
        System.out.println("折叠的");
        brand.play();
    }
    public void music(){
    
    
        System.out.println("折叠的");
        brand.music();
    }
    public void video(){
    
    
        System.out.println("折叠的");
        brand.video();
    }
}

Specific features of touchscreen phones

public class Touch extends Phone {
    
    
    public Touch(Brand brand) {
    
    
        super(brand);
    }
    public void play(){
    
    
        System.out.println("触屏的");
        brand.play();
    }
    public void music(){
    
    
        System.out.println("触屏的");
        brand.music();
    }
    public void video(){
    
    
        System.out.println("触屏的");
        brand.video();
    }
}

Test customers:

public class Client {
    
    
    public static void main(String[] args) {
    
    
        FoldPhone foldPhone = new FoldPhone(new Huawei());
        foldPhone.play();
        foldPhone.music();
        foldPhone.video();

        Touch touch = new Touch(new Huawei());
        touch.music();
        touch.play();
        touch.video();
    }
}

result:

折叠的
华为手机玩游戏
折叠的
华为手机听音乐
折叠的
华为手机看视频
触屏的
华为手机听音乐
触屏的
华为手机玩游戏
触屏的
华为手机看视频

Process finished with exit code 0

When a mobile phone with an upright style needs to be newly added, it is only necessary to re-inherit the abstract mobile phone class, and then write the functions that should be unique to the upright mobile phone.

decorator pattern

Decorator mode: Dynamically attach new functions to objects. In terms of object function extension, it is more flexible than inheritance, reflecting the principle of opening and closing

FlyWeight Pattern

Shared objects
In java, this mode can solve the problem of memory waste of repeated objects. When the similarity of requirements is high, you can consider using the flyweight mode to solve it. For example, the creation of String strings and thread pools uses the flyweight mode
insert image description herediagram illustrate:

  1. FlyWeight: It is an abstract flyweight role. It is an abstract class of the product, and at the same time defines the external state of the object (state that is easy to change, information that cannot be shared between objects) and internal state (state that is not easy to change, between objects shareable information) interface or implementation class.
  2. ConcreteFlyWeight is a specific flyweight role, a specific product category, and realizes abstract role-related businesses
  3. UnsharedConcreteFlyweight is a role that cannot be shared and generally does not appear in flyweight factories
  4. Factory is a flyweight factory class, which is used to build a pool container, and also provides a method to obtain objects from the pool.
    code display
//外部状态,针对不同的使用者来使用网站
public class User {
    
    
   private String name;
   public User(String name){
    
    
       this.name=name;
   }
}

//共享的抽象类
public abstract class FlyWeight {
    
    
    public abstract void use(User user);
}

//具体的实现类
public class ConcreteFlyWeight extends FlyWeight {
    
    
    private String type="";
    public ConcreteFlyWeight(String type){
    
    
        this.type=type;
    }

    @Override
    public void use(User user) {
    
    

        System.out.println(user+"当前正在使用"+type);
    }
}


//工厂类
public class flyWeightFactory {
    
    

    private static HashMap<String,FlyWeight> pool=new HashMap<>();
    public static FlyWeight getConcrete(String type){
    
    
        if(!pool.containsKey(type)){
    
    
            ConcreteFlyWeight weight = new ConcreteFlyWeight(type);
            pool.put(type,weight);
        }
        return pool.get(type);
    }
    public static int poolSize(){
    
    
        return pool.size();
    }
}

//测试类
public class WebTest {
    
    
    public static void main(String[] args) {
    
    
        FlyWeight concrete = flyWeightFactory.getConcrete("知乎");
        concrete.use(new User("小明"));
        FlyWeight weight = flyWeightFactory.getConcrete("斗鱼");
        weight.use(new User("zhangsan"));
        FlyWeight weight1 = flyWeightFactory.getConcrete("斗鱼");
        weight1.use(new User("历史"));
        FlyWeight weight2 = flyWeightFactory.getConcrete("斗鱼");
        weight2.use(new User("王维护"));
        System.out.println("线程池中的对象数:"+flyWeightFactory.poolSize());
    }
}


Test results: It can be seen that although 4 objects are used, there are only 2 objects in the pool at the end

User{
    
    name='小明'}当前正在使用知乎
User{
    
    name='zhangsan'}当前正在使用斗鱼
User{
    
    name='历史'}当前正在使用斗鱼
User{
    
    name='王维护'}当前正在使用斗鱼
线程池中的对象数:2

Process finished with exit code 0

Guess you like

Origin blog.csdn.net/m0_56184347/article/details/120656500