This is the 13th day of my participation in Gwen Challenge

Design patterns

Using design patterns, we can make our code more readable, extensible, readable, reusable, highly cohesive and low-coupling. As programmers, it is a concept that we often hear, and one that we programmers must learn and understand deeply.

Types of design patterns

The tables and figures are from the Rookie tutorial

The serial number Pattern & Description including
1 Creation patternThese design patterns provide a way to hide the creation logic while creating objects, rather than instantiating objects directly using the new operator. This gives the program more flexibility in deciding which objects to create for a given instance. Abstract Factory Pattern Singleton Pattern Builder Pattern Prototype The Pattern)
2 Structural modeThese design patterns focus on combinations of classes and objects. The concept of inheritance is used to combine interfaces and define how composite objects acquire new functionality. Adapter Pattern Bridge Pattern Filter Pattern Composite Pattern Decorator Pattern Pattern Facade Pattern Flyweight Pattern Proxy Pattern
3 Behavioral patternThese design patterns are particularly concerned with communication between objects. Chain of Responsibility Pattern Command Pattern Interpreter Pattern Iterator Pattern Mediator Pattern Observer Pattern State Pattern Null Object Pattern Strategy Pattern (Template Pattern)
4 J2EE patternsThese design patterns pay particular attention to the presentation layer. These patterns were identified by the Sun Java Center. MVC Pattern Business Delegate Pattern Composite Entity Pattern Data Access Object Pattern Front Controller Pattern Intercepting Filter Pattern Service Locator Pattern Transfer Object Pattern

Here is a picture to describe the overall relationship between design patterns:

The seven principles

1. Single Responsibility Principle

Functional dependencies between component elements of a module. A class has only one responsibility.

2. Liskov Substitution Principle

One of the basic principles of object-oriented design. Wherever a base class can appear, subclasses can, and derived classes can add new behavior to the base class. The specification is not mandatory for subclasses to follow these contracts, but it cannot be modified arbitrarily, which reduces the portability of programs and increases the coupling of programs (changes to the base class affect all subclasses).

3, Dependence Inversion Principle

This principle is the basis of the open closed principle, which relies on abstraction rather than on concrete, and the core idea is interface programming.

4. Interface Segregation Principle

The number of interfaces can be increased to ensure that one class depends on the minimum interface of the other class, and each class needs its own special interface. For example, if B depends on interfaces 1 and 2 of A, and C depends on interfaces 3 and 4 of A, you can isolate interfaces 1 and 2 as new interfaces.

5. Demeter Principle, also known as the Least Known Principle

One entity should interact with other entities as little as possible so that the functional modules of the system are relatively independent.

Composite Reuse Principle

Try to use composition/aggregation rather than inheritance.

7. Open Close Principle

Open for extensions, closed for modifications. Through the use of interfaces and abstract classes to achieve when the program needs to be extended, can not modify the original code, to achieve a hot plug effect.

Single responsibility principle

The single responsibility principle expresses the functional dependencies between the components of a module. A class has only one responsibility.

At first, the business was just one type of animal, herbivores, and that’s what we wrote in our code.

package com.wangscaler.singleresponsibility;

/ * * *@author wangscaler
 * @date2021.06.16 assembling of * /
public class SingleResponsibilityPrinciple {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.eat("Cow");
        animal.eat("Sheep");
        animal.eat("Horse"); }}class Animal {
    public void eat(String type) {
        System.out.println(type + "Eat grass"); }}Copy the code

And that’s perfectly fine, as the business grows and we find that we add carnivores, if we just write animal.eat; This violates our principle of single responsibility and is clearly inappropriate. Then our code needs to be rewritten.

Correct case 1 is as follows:

package com.wangscaler.singleresponsibility;

/ * * *@author wangscaler
 * @date2021.06.16 assembling of * /
public class SingleResponsibilityPrinciple {
    public static void main(String[] args) {
        Carnivorous carnivorous = new Carnivorous();
        Herbivorous herbivorous = new Herbivorous();
        herbivorous.eat("Cow");
        herbivorous.eat("Sheep");
        herbivorous.eat("Horse");
        carnivorous.eat("Tiger");
        carnivorous.eat("The lion"); }}class Herbivorous {
    public void eat(String type) {
        System.out.println(type + "Eat grass"); }}class Carnivorous {
    public void eat(String type) {
        System.out.println(type + "Eat meat." "); }}Copy the code

This change, obviously consistent with the single responsibility principle, can be used when there are many methods under a class. There are fewer methods here, so it’s expensive to write it this way, so you can violate the single-responsibility principle of the class, and keep the methods single-responsibility.

Correct Case 2:

package com.wangscaler.singleresponsibility;

/ * * *@author wangscaler
 * @date2021.06.16 assembling of * /
public class SingleResponsibilityPrinciple2 {
    public static void main(String[] args) {
        Animals animals = new Animals();
        animals.herbivorousEat("Cow");
        animals.carnivorousEat("Tiger"); }}class Animals {
    public void herbivorousEat(String type) {
        System.out.println(type + "Eat grass");
    }

    public void carnivorousEat(String type) {
        System.out.println(type + "Eat meat." "); }}Copy the code

This way, when we add a class, we just need to add a new class method, and the previous code doesn’t need to be touched. Like when we add animals that eat both meat and grass. I just need to do this.

package com.wangscaler.singleresponsibility;

/ * * *@author wangscaler
 * @date2021.06.16 assembling of * /
public class SingleResponsibilityPrinciple2 {
    public static void main(String[] args) {
        Animals animals = new Animals();
        animals.herbivorousEat("Cow");
        animals.carnivorousEat("Tiger");
        // Don't care whether pandas eat meat or grass.
        animals.eat("Panda"); }}class Animals {
    public void herbivorousEat(String type) {
        System.out.println(type + "Eat grass");
    }

    public void carnivorousEat(String type) {
        System.out.println(type + "Eat meat." ");
    }

    public void eat(String type) {
        System.out.println(type + "Eat meat and grass."); }}Copy the code

As we can see, we now only need to add the code for the new business, and the code we wrote before has no impact.

** Summary: ** The key to the single responsibility principle is to separate the responsibilities of different classes in the business into different classes or interfaces. The principle is that a method should handle as many responsibilities as possible, but there must be relationships between them, which should be separated by business and requirements. If there are many methods, it is best to isolate them on the class. If there are few methods and the logic is simple, you can have the class violate the single responsibility principle and let the method keep it.

Interface Isolation Principle

The number of interfaces can be increased to ensure that a class depends on the minimum interface of another class. Special interfaces should be established for each class. The interfaces should be as detailed as possible, with one interface corresponding to one function module and fewer methods in the interface to make the interface more portable and flexible. For example, if B depends on interfaces 1 and 2 of A, and C depends on interfaces 3 and 4 of A, interfaces 1 and 2 can be isolated as new interfaces. 3 and 4 are isolated as new interfaces.

Examples of errors:

Originally our interface was to write all the behaviors, whereas horses only rely on eat, run; Ducks depend on eat, run, swim; Swans rely on all methods. It would be illogical to implement the fly method, which is obviously useless for horses.

package com.wangscaler.interfacesegregation;

/ * * *@author wangscaler
 * @date2021.06.16 now * /
public class InterfaceSegregationPrinciple {
    public static void main(String[] args) {
        IAction horse = new Horse();
        horse.eat();


    }

    interface IAction {
        void eat(a);

        void fly(a);

        void run(a);

        void swim(a);
    }

    static class Horse implements IAction {

        public void eat(a) {
            System.out.println("Horses eat.");
        }

        public void fly(a) {}public void run(a) {
            System.out.println("The horse can walk.");
        }

        public void swim(a) {}}class Duck implements IAction {

        public void eat(a) {
            System.out.println("Ducks eat.");
        }

        public void fly(a) {}public void run(a) {
            System.out.println("Ducks can walk.");
        }

        public void swim(a) {
            System.out.println("Ducks can swim."); }}class swan implements IAction {

        public void eat(a) {
            System.out.println("Swans will eat.");
        }

        public void fly(a) {
            System.out.println("Swans can fly");
        }

        public void run(a) {
            System.out.println("Swans can walk.");
        }

        public void swim(a) {
            System.out.println("Swans can swim."); }}}Copy the code

It is found that all animals have the behaviors of eat and run, while fly and swim are unique behaviors, so the interfaces are changed according to the interface isolation principle as follows:

Correct example.

package com.wangscaler.interfacesegregation;

/ * * *@author wangscaler
 * @date2021.06.16 now * /
public class InterfaceSegregationPrinciple1 {
    public static void main(String[] args) {
        Horse horse = new Horse();
        horse.eat();
        horse.run();
    }

    interface IEatAndRunAction {
        void eat(a);

        void run(a);
    }

    interface IFlyAction {
        void fly(a);
    }

    interface ISwimAction {
        void swim(a);
    }

    static class Horse implements IEatAndRunAction {

        public void eat(a) {
            System.out.println("Horses eat.");
        }

        public void run(a) {
            System.out.println("The horse can walk."); }}class Duck implements IEatAndRunAction.ISwimAction {

        public void eat(a) {
            System.out.println("Ducks eat.");
        }

        public void run(a) {
            System.out.println("Ducks can walk.");
        }

        public void swim(a) {
            System.out.println("Ducks can swim."); }}class swan implements IEatAndRunAction.ISwimAction.IFlyAction {

        public void eat(a) {
            System.out.println("Swans will eat.");
        }

        public void fly(a) {
            System.out.println("Swans can fly");
        }

        public void run(a) {
            System.out.println("Swans can walk.");
        }

        public void swim(a) {
            System.out.println("Swans can swim."); }}}Copy the code

Conclusion: the granularity of ** interfaces must be reasonable, too small will lead to more interfaces, too large will lead to reduced flexibility, reduce code redundancy, improve the cohesion of the system.