30 - design principles and design patterns

Posted by fitchn on Wed, 16 Feb 2022 11:42:02 +0100

Design principles and design patterns

Common design principles----------------------------------------
Software development process: requirements analysis document, outline design document, detailed design document, coding and testing, installation and debugging, maintenance and upgrading
Common design principles----------------------------------------
Open Close Principle: open to extension and close to modification. In order to make the program extensible and easy to maintain and upgrade
package com.lagou.task21;

public abstract class Person {
    private String name;
    //private int age;
    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public abstract void show();
}

package com.lagou.task21;

public class SubPerson extends Person {
    private int age;

    @Override
    public void show() {

    }
}

Liskov Substitution Principle: Where any base class can appear, subclasses must appear, and polymorphic methods are often used
package com.lagou.task09;

/**
 *
 */
public class ShapeTest {
    //The custom member method implements the behavior of printing the characteristics of the rectangular object specified by the parameter
    //That is, the behavior of drawing graphics
    //Rect r = new Rect(1,2,3,4);
    //public static void draw(Rect r){
    //    r.show(); // 1 2 3 4
    //}
    //The custom member method implements the behavior of printing the characteristics of circular objects specified by parameters
    //public static void draw(Circle c) {/ / overload
    //    c.show(); // 1 2 3
    //}
    //The custom member method can print both rectangular objects and circular objects
    //The object is passed in by parameters, and the subclass is a parent class
    //Shape r = new Rect(1,2,3,4);
    //Shape r = new Circle(1,2,3);
    //Polymorphism is one of the applications of polymorphism. Polymorphism is formed through parameter transmission
    public static void draw(Shape s){ //heavy load
        // The reference of the parent type points to the object of the child type, which is polymorphism
        //The compilation stage calls the version of the parent class, and the runtime stage calls the rewritten version of the child class
        s.show(); // 1 2 3 4
    }
    public static void main(String[] args) {
        //Rect r = new Rect(1,2,3,4);
        ShapeTest.draw(new Rect(1,2,3,4));
        ShapeTest.draw(new Circle(1,2,3));


    }
}

Dependency Inversion Principle: rely on abstract classes or interfaces rather than concrete implementation classes as much as possible, and have mandatory and normative interfaces for subclasses
That is, try to have abstract classes and interfaces
Interface aggregation principle: try to use small interfaces instead of large ones to avoid interface pollution and reduce coupling between classes
package com.lagou.task21;

public interface Animal {

    void run(); // Abstract method for describing running behavior
    void fly(); // Abstract method for describing flight behavior
}

package com.lagou.task21;

public interface RunAnimal {

    void run(); // Abstract method for describing running behavior
}

package com.lagou.task21;

public interface FlyAnimal {

    void fly(); // Abstract method for describing flight behavior
}

package com.lagou.task21;

public class Dog implements RunAnimal {
    @Override
    public void run() {

    }
}

Demeter Principle: an entity should interact with other entities as little as possible
Make the system functional modules relatively independent. High cohesion and low coupling. Similar to the isolation principle, there is no operation of other classes, but as independent as possible
And try not to operate other types of operations
Composite Reuse Principle: try to use composition / aggregation rather than inheritance
package com.lagou.task21;

public class A {

    public void show() {
        System.out.println("This is A Class show method!");
    }
}

package com.lagou.task21;

public class B/* extends A*/ {
    private A a;  // Synthetic Reuse Principle

    public B(A a) {
        this.a = a;
    }

    public void test() {
        // How to call the show method in class A?
        a.show();
    }
}

Common design patterns----------------------------------------
Design pattern is a summary of code design experience that is repeatedly used, known by most people, classified and catalogued
Design pattern is a fixed routine for fixed occasions
Basic classification----------------------------------------
Creative pattern - singleton design pattern, factory method pattern, abstract factory pattern
Structural mode - decorator mode, agent mode
Behavioral pattern - template design pattern
Detailed explanation of design mode----------------------------------------
Singleton design mode: singleton design mode is mainly divided into starving type and lazy type. Lazy type requires synchronous processing of multiple threads
package com.lagou.task21;

public class Singleton {

    // 2. Declare that the reference of this class type points to the object of this class type and use the private static keyword to modify it
    private static Singleton sin = null;

    // 1. The privatization construction method is modified with the private keyword
    private Singleton() {}

    // 3. Provide a public get method, which is responsible for returning the above objects and modifying them with the public static keyword
    public static /*synchronized*/ Singleton getInstance() {
        /*synchronized (Singleton.class) {
            if (null == sin) {
                sin = new Singleton();
            }
            return sin;
        }*/
        if (null == sin) {
            synchronized (Singleton.class) {
                if (null == sin) {
                    sin = new Singleton();
                }
            }
        }
        return sin;
    }
}

Ordinary factory mode: the ordinary factory method mode is to create a factory class and create instances of different implementation classes that implement the same interface
Class diagram structure

Main disadvantage: in the normal factory method mode, if the string passed is wrong, the object cannot be created correctly, and a null pointer exception may occur
package com.lagou.task21;

public interface Sender {
    // Customize abstract methods to describe the sending behavior
    void send();
}

package com.lagou.task21;

public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("Sending mail...");
    }
}

package com.lagou.task21;

public class SmsSender implements Sender {
    @Override
    public void send() {
        System.out.println("Sending SMS...");
    }
}

package com.lagou.task21;

public class SendFactory {
    // The custom member method implements the creation of objects
    public Sender produce(String type) {
        //System.out.println("add a sentence to print and test");
        if ("mail".equals(type)) {
            return new MailSender();
        }
        if ("sms".equals(type)) {
            return new SmsSender();
        }
        return null;
    }
   //Multiple factories
    public static Sender produceMail() {
        return new MailSender();
    }
    public static Sender produceSms() {
        return new SmsSender();
    }
}

package com.lagou.task21;

public class SendFactoryTest {

    public static void main(String[] args) {

        // Disadvantages: the code is complex and the readability is slightly poor
        // Advantages: stronger expansibility and maintainability! Especially on the premise of creating a large number of objects
        //For example, if you need to print a sentence in front of the object, you can write a sentence directly in the method here
        //You can deal with a large number of object creation operations. Otherwise, you will write a lot of printed code
        // 1. Declare that the reference of factory class type points to the object of factory class type
        //SendFactory sf = new SendFactory();
        // 2. Call the production method to create the object
        //Sender sender = sf.produce("mail");
        //Sender sender = sf.produce("maill");
        //Sender sender = sf.produceMail();
        Sender sender = SendFactory.produceMail();
        // 3. Use object call method to simulate the behavior
        sender.send();

        System.out.println("-------------------------------------");
        // Advantages: simple code, strong readability, and advantages in creating a single object
        // Disadvantages: poor scalability and maintainability
        Sender sender1 = new MailSender();
        sender1.send();

        System.out.println("-------------------------------------");
        Provider provider = new MailSendFactory();
        Sender sender2 = provider.produce();
        sender2.send();

        System.out.println("-------------------------------------");
        Provider provider1 = new PacketSendFactory();
        Sender sender3 = provider1.produce();
        sender3.send();
    }
}

Multiple factory method patterns
Class diagram structure

Practical significance: the factory method mode is suitable: when a large number of products need to be created and have common interfaces, they can be created through the factory method mode
Main disadvantages: a problem with factory method mode is that the creation of classes depends on factory classes, that is, if you want to expand programs to produce new products,
The code of the factory class must be modified, which violates the opening and closing principle
Abstract factory pattern----------------------------------------
Class diagram structure

package com.lagou.task21;

public interface Provider {
    // User defined abstract method to describe the production behavior of products
    Sender produce();
}

package com.lagou.task21;

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

package com.lagou.task21;

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

package com.lagou.task21;

public class PacketSender implements Sender {
    @Override
    public void send() {
        System.out.println("Sending package...");
    }
}

package com.lagou.task21;

public class PacketSendFactory implements Provider {
    @Override
    public Sender produce() {
        return new PacketSender();
    }
}

Decorator mode----------------------------------------
Decorator mode is to dynamically add some new functions to an object, which requires that the decorated object and the decorated object implement the same interface, and the decorated object holds the instance of the decorated object
Class diagram structure

Practical significance: it can realize the extension of a class function. You can add functions dynamically and undo them dynamically (inheritance doesn't work)
Disadvantages: too many similar objects are generated, which is not easy to troubleshoot
package com.lagou.task21;

public interface Sourceable {
    // Custom abstract method
    void method();
}

package com.lagou.task21;

public class Source implements Sourceable {
    @Override
    public void method() {
        System.out.println("Plain beauty can be so beautiful!");
    }
}

package com.lagou.task21;

public class Decorator implements Sourceable {
    private Sourceable source;

    public Decorator(Sourceable source) {
        this.source = source;
    }

    @Override
    public void method() {
        source.method(); // Ensure that the original functions remain unchanged
        System.out.println("You will be more beautiful after make-up!");
    }
}

package com.lagou.task21;

public class SourceableTest {

    public static void main(String[] args) {

        Sourceable sourceable = new Source();
        sourceable.method();

        System.out.println("---------------------------------------------------");
        // Next, use the decoration class to realize the function
        Sourceable sourceable1 = new Decorator(sourceable);
        sourceable1.method();

        System.out.println("---------------------------------------------------");
        Sourceable sourceable2 = new Proxy();
        sourceable2.method();
    }
}

package com.lagou.task21;

public class Proxy implements Sourceable {
    private Source source;

    public Proxy() {
        source = new Source();
    }

    @Override
    public void method() {
        source.method();
        System.out.println("I'm actually different from the decorator mode!");
    }
}

Agent mode----------------------------------------
Proxy mode is to find a proxy class to perform some operations for the original object
For example, when we rent a house, we find an intermediary. Another example is that we need to hire a lawyer to file a lawsuit. The intermediary and lawyer are our agents here
Class diagram structure

Practical significance
If you need to improve the original method when using it, you can use a proxy class to call the original method
And control the results, which is the agent mode. Using the agent mode, the functions can be divided more clearly, which is helpful for later maintenance
Comparison between agent mode and decorator mode----------------------------------------------
Decorator mode usually passes the original object as a parameter to the decorator's constructor
The proxy mode usually creates an object of the proxy class in a proxy class
The decorator pattern focuses on dynamically adding methods to an object, while the proxy pattern focuses on controlling access to objects
Template method mode----------------------------------------
Template method pattern mainly refers to the encapsulation of a fixed process in an abstract class
The specific steps in the process can be implemented differently by different subclasses, and the fixed process can produce different results through abstract classes
Class diagram structure

Practical significance
Extract the content shared by multiple subclasses with basically the same logic to realize code reuse. Different subclasses achieve different effects and form polymorphism, which is helpful for later maintenance
package com.lagou.task21;

public abstract class AbstractCalculator {

    // The custom member method cuts the expression specified by the parameter according to the rules specified by the parameter and returns the calculation result of 1 + 1+
    public int splitExpression(String exp, String op) {
        String[] sArr = exp.split(op);
        return calculate(Integer.parseInt(sArr[0]), Integer.parseInt(sArr[1]));
    }

    // User defined abstract method to realize operation
    public abstract int calculate(int ia, int ib);
}

package com.lagou.task21;

public class Plus extends AbstractCalculator {
    @Override
    public int calculate(int ia, int ib) {
        return ia + ib;
    }
}

package com.lagou.task21;

public class Minus extends AbstractCalculator {
    @Override
    public int calculate(int ia, int ib) {
        return ia - ib;
    }
}

package com.lagou.task21;

public class AbstractCalculatorTest {

    public static void main(String[] args) {

        AbstractCalculator abstractCalculator = new Plus();
        int res = abstractCalculator.splitExpression("1+1", "\\+");
        System.out.println("The final calculation result is:" + res); // 2
    }
}

   public int calculate(int ia, int ib) {
        return ia + ib;
    }
}

package com.lagou.task21;

public class Minus extends AbstractCalculator {
    @Override
    public int calculate(int ia, int ib) {
        return ia - ib;
    }
}

package com.lagou.task21;

public class AbstractCalculatorTest {

    public static void main(String[] args) {

        AbstractCalculator abstractCalculator = new Plus();
        int res = abstractCalculator.splitExpression("1+1", "\\+");
        System.out.println("The final calculation result is:" + res); // 2
    }
}

Topics: Java