Learning notes - Java design pattern - structured pattern 3

Keywords: Algorithm

Java design principles & & patterns learning notes

explain

Recently, the sweeper decided to integrate the design mode learned at the beginning of the year. First, it is used for review and consolidation. Second, he also hopes to encourage his integration with students in need.

In the course of learning, the main reference of the sweeper is the related notes of the official account of "dime technology". I would like to express my heartfelt thanks to these writers and floor sweepers.

Reference article 1-Java design principles

Reference article 2 - Summary of Java design patterns

Refer to Article 3-23 shorthand of design patterns

4. Structural model

4.5 structural mode 5 - Flyweight mode

Shorthand key words: Chinese character coding

brief introduction

Definition: use sharing technology to effectively support a large number of fine-grained objects.

The meta model requires fine-grained objects, which will lead to a large number of objects with similar properties. Therefore, we divide the object information into two parts: internal state and external state:

  • Internal state: the information shared by the object is stored in the shared meta object and will not change with the environment;
  • External state: it is a mark that an object can rely on. It changes with the change of the environment and cannot be shared;

In a system, objects will occupy too much memory, especially those with a large number of repeated objects, which is a great waste of system resources. Sharing meta pattern provides a solution for object reuse, which uses sharing technology to reuse the same or similar objects. Sharing meta pattern is to run sharing technology to effectively support the reuse of a large number of fine-grained objects. The system uses a small number of objects, which are similar and have small state changes, so it can realize multiple reuse of objects. Here's a point to note: the shared meta pattern requires that the objects that can be shared must be fine-grained objects. Sharing mode greatly reduces the number of objects in the system through sharing technology. At the same time, sharing mode uses internal state and external state. At the same time, the external state is relatively independent and will not affect the internal state. Therefore, sharing mode can enable sharing objects to be shared in different environments. At the same time, it is divided into internal state and external state. The meta sharing mode will make the system more complex, and it will also lead to a long time to read the external state.

Problems solved

Shared meta mode can solve the problem of memory waste of duplicate objects. When there are a large number of similar objects in the system and a buffer pool is required. Instead of always creating objects, you can take them from the buffer pool. This can reduce system memory and improve efficiency.

Mode composition

Composition (role) effect
Flyweight Abstract metaclass
ConcreteFlyweight concrete meta class
UNsharedConcreteFlyweight unshared concrete meta class
FlyweightFactory class

example

package top.saodisheng.designpattern.flyweight;

import java.util.HashMap;

/**
 * description:
 *
 * @author Sweeper_ saodisheng
 * @date 2021-02-05
 */
public class FlyWeightPattern {
    public static void main(String[] args) {

        Flyweight flyweight1 = FlyweightFactory.getFlyweight("1");
        Flyweight flyweight2 = FlyweightFactory.getFlyweight("1");
        Flyweight flyweight3 = FlyweightFactory.getFlyweight("2");

    }
}

/**
 * 1. Abstract meta class, an abstract class that defines the internal state and external state or implementation of an object
 */
abstract class Flyweight {

    /** Internal state**/
    private String intrinsic;
    /** External state**/
    protected  final String Extrinsic;

    /**
     * It is required that the meta role must accept external status
     * @param Extrinsic
     */
    public Flyweight(String Extrinsic){
        this.Extrinsic = Extrinsic;
        System.out.println(" Extrinsic: "+ Extrinsic +" created. ");
    }

    /**
     * Define business operations
     */
    public abstract void operate();

    /**
     * getter/setter of internal state
     * @return
     */
    public String getIntrinsic() {
        return intrinsic;
    }

    public void setIntrinsic(String intrinsic) {
        this.intrinsic = intrinsic;
    }
}

/**
 * 2. Define a specific meta class and a specific product class. It should be noted that the internal state processing should be independent of the environment,
 * There should not be an operation that changes both the external state and the internal state
 */
class ConcreteFlyweight extends Flyweight {

    /** Accept external status**/
    public ConcreteFlyweight(String Extrinsic){
        super(Extrinsic);
    }

    /**
     * Logical processing according to external state
     */
    @Override
    public void operate() {
        //Business logic
    }
}

/**
 * 3. Create a meta factory, construct a pool container, and provide methods to get objects from the pool
 */
class FlyweightFactory {
    /** Define a pool container**/
    private static HashMap<String, Flyweight> pool=new HashMap<String, Flyweight>();
    /** Xiangyuan factory**/
    public static Flyweight getFlyweight(String Extrinsic){
        //Object to return
        Flyweight flyweight = null;
        //If you have this object in the pool, you can get it directly from the pool
        if (pool.containsKey(Extrinsic)){
            flyweight = pool.get(Extrinsic);
        }else {
            //If the object does not exist in the pool, one is created and placed in the pool
            flyweight = new ConcreteFlyweight(Extrinsic);
            pool.put(Extrinsic,flyweight);
        }
        return flyweight;
    }
}

The results show that the external status of 1 is created only once.

Advantages and disadvantages

Advantages: if the system has a large number of similar objects, it can save a lot of memory and CPU resources.

Disadvantages: it increases the complexity of the system, needs to separate the external state and the internal state, and the external state has fixed attributes and should not change with the change of the internal state.

Application scenario

It is often used in the bottom development of the system to solve the performance problems of the system. Like the database connection pool, there are created connection objects. Among these connection objects, we can use them directly to avoid re creation. If we don't have what we need, create one.

A scene in which there are a large number of similar objects in a system and a buffer pool is required. Instead of creating a new object all the time, you can get it directly from the buffer pool. This can reduce system memory and improve efficiency.

  • There are a large number of similar objects in the system;
  • Fine grained objects have close external states, and the internal state is independent of the environment;
  • Scenarios requiring buffer pools

Application in source code

#JDK
String,Integer,Long...
com.sun.org.apache.bcel.internal.generic.InstructionConstants
......

4.6 structural mode 6 - Facade mode (appearance mode, Facade)

Shorthand key words: external unified interface

brief introduction

Definition: provide a consistent interface for a group of interfaces in the subsystem. The Facade pattern defines a high-level interface, which makes the subsystem easier to use.

By creating a unified appearance class to wrap one or more complex classes in the subsystem, the client can call all methods in the internal subsystem by calling the methods of the appearance class.

Problems solved

  • High coupling between systems is avoided
  • Make complex subsystem usage simple

example

package top.saodisheng.designpattern.facade;

/**
 * description:
 *
 * @author Sweeper_ saodisheng
 * @date 2021-02-06
 */
public class FacadePattern {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.MethodA();
        facade.MethodB();
        System.out.println("----over----");
    }
}

/**
 * 1. Define subsystem
 */
class SubSystemOne {
    public void methodOne() {
        System.out.println("Subsystem method I");
    }
}

class SubSystemTwo {
    public void methodTwo() {
        System.out.println("Subsystem method II");
    }
}

class SubSystemThree {
    public void methodThree() {
        System.out.println("Subsystem method III");
    }
}

class SubSystemFour {
    public void methodFour() {
        System.out.println("Subsystem method IV");
    }
}

/**
 * 2. Define appearance classes
 */
class Facade {
    SubSystemOne one;
    SubSystemTwo two;
    SubSystemThree three;
    SubSystemFour four;

    public Facade() {
        this.one = new SubSystemOne();
        this.two = new SubSystemTwo();
        this.three = new SubSystemThree();
        this.four = new SubSystemFour();
    }

    public void MethodA() {
        System.out.println("Method group A()----");
        one.methodOne();
        two.methodTwo();
        four.methodFour();
    }

    public void MethodB() {
        System.out.println("Method group B()----");
        two.methodTwo();
        three.methodThree();
    }
}

Advantages and disadvantages

advantage:

  • Reduce system interdependence
  • Appearance mode provides a unified interface to the upper module by encapsulating the subsystem, so as to reduce the excessive coupling between the upper module and the subsystem
  • Increased flexibility
  • Improve security

Disadvantages: it does not conform to the opening and closing principle - when the appearance is not abstracted, if a new subsystem needs to be added, the Facade needs to be modified

Application scenario

  1. To provide a simple interface for a complex subsystem

  2. Provide subsystem independence

  3. There is a large dependency between the client program and multiple subsystems

  4. In the hierarchy, appearance patterns can be used to define the entry of each layer in the system

Difference from adapter mode

The core of the implementation of the appearance pattern is that the appearance class saves the references of each subsystem, and a unified appearance class wraps multiple subsystem classes. However, the client only needs to reference this appearance class, and then the appearance class calls the methods in each subsystem.

Application in source code

#tomcat
org.apache.catalina.connector.RequestFacade
org.apache.catalina.connector.ResponseFacade
#mybatis
Configuration
......

4.7 structural mode 7 - Bridge mode

Shorthand Keywords: inheritance tree splitting

brief introduction

Definition: separate the abstract part from its implementation part so that they can change independently. It is implemented by replacing inheritance relationship with composition relationship, which reduces the coupling between abstraction and implementation.

If a system can be classified from multiple angles, and each classification may change, what we need to do is to separate these angles, so that they can change independently and reduce the coupling between them. This separation process uses the bridge mode. The so-called bridge mode is to isolate the abstract part from the implementation part, so that they can change independently. The bridging mode transforms the inheritance relationship into association relationship, encapsulates the change, completes the decoupling, reduces the number of classes in the system and the amount of code.

Pattern implementation

package top.saodisheng.designpattern.bridge.v1;

/**
 * description:
 * Bridging mode
 *
 * @author Sweeper_ saodisheng
 * @date 2021-02-05
 */
public class BridgePattern {
    public static void main(String[] args) {
        Implementor imple = new ConcreteImplementorA();
        Abstraction abs = new RefinedAbstraction(imple);
        abs.Operation();
    }
}

/**
 * 1. Define implementation interfaces
 */
interface Implementor {
    void OperationImpl();
}

/**
 * 2. Define concrete implementation classes
 */
class ConcreteImplementorA implements Implementor {

    @Override
    public void OperationImpl() {
        System.out.println("The materialized class is accessed");
    }
}

/**
 * 3. Define abstract classes
 */
abstract class Abstraction {
    protected Implementor imple;

    protected Abstraction(Implementor imple) {
        this.imple = imple;
    }
    public abstract void Operation();
}

/**
 * 4. Extended abstract class
 */
class RefinedAbstraction extends Abstraction {

    protected RefinedAbstraction(Implementor imple) {
        super(imple);
    }

    @Override
    public void Operation() {
        System.out.println("The extension abstraction class is accessed");
        imple.OperationImpl();
    }
}

Problems solved

When there are many possible changes, inheritance will cause explosion and inflexible expansion

Mode composition

You can separate the abstract part from the implementation part, cancel the inheritance relationship between them, and use the combination relationship instead.

Composition (role) effect
Abstraction role Defines an abstract class and contains a reference to an implementation object
Extended abstraction role It is a subclass of the abstract role, which implements the business methods in the parent class, and calls the business methods in the abstract role through the composition relationship
Implementer role Define the interface to implement the abstract role, which can be called by the extended abstract role
Concrete implementer role The specific implementation of the implementation role interface is given

Example description

A company has developed a financial management system, in which there is a tool module of report generator. Customers can specify any report type, such as basic report, transaction report, fund report, asset report, etc., and can specify different report styles, such as pie chart, histogram, etc. The system designer designed the class diagram shown in the figure below for the structure of the report generator.

Later, during the customer's use, the customer wanted to add a new report and a new line graph. At this time, the developer found that the maintenance was very troublesome. After careful analysis, the designer found that there were serious problems, because adding a new report or graph required adding many subclasses. Therefore, the system analyst finally reconstructed the above scheme according to the object-oriented design principle. The reconstructed figure is as follows.

In this reconstruction scheme, the report and graphics are designed into two inheritance structures, both of which can be changed independently. When programming, you can only code for abstract classes, and then inject specific graphic subclass objects into specific report classes at run time. In this way, the system has good scalability and maintainability, and meets the opening and closing principle of object-oriented design principle.

Use steps

package top.saodisheng.designpattern.bridge.v2;

/**
 * description:
 * Bridging mode
 *
 * @author Sweeper_ saodisheng
 * @date 2021-02-05
 */
public class BridgePattern {
    public static void main(String[] args) {
        //Separation of realization and abstraction

        // Basic report
        IReport basicReport = new BasicReport();
        // Current statement
        IReport intercourseReport = new IntercourseReport();
        // Fund statement
        IReport capitalReport = new CapitalReport();

        // Basic report using histogram
        AbstractionGraph barchart = new Barchart(basicReport);
        barchart.operation();

        // Pie chart for basic report
        AbstractionGraph piechart = new Piechart(basicReport);
        piechart.operation();
    }
}

/**
 * 1 Define an implementation role and report interface
 */
interface IReport {
    void operationImpl();
}

/**
 * 2 Define specific implementation roles (basic report, transaction report, fund report)
 */
class BasicReport implements IReport {

    @Override
    public void operationImpl() {
        System.out.println("Basic report accessed");
    }
}

class IntercourseReport implements IReport {

    @Override
    public void operationImpl() {
        System.out.println("Transaction report accessed");
    }
}

class CapitalReport implements IReport {

    @Override
    public void operationImpl() {
        System.out.println("Fund report accessed");
    }
}

/**
 * 3 Define abstract roles, graphics
 */
abstract class AbstractionGraph{
    protected IReport iReport;

    public AbstractionGraph(IReport iReport) {
        this.iReport = iReport;
    }
    abstract void operation();
}

/**
 * 4 Define extended abstraction roles (histogram, pie chart)
 */
class Barchart extends AbstractionGraph {
    public Barchart(IReport iReport) {
        super(iReport);
    }

    @Override
    void operation() {
        System.out.println("Histogram accessed.");
        iReport.operationImpl();
    }
}

class Piechart extends AbstractionGraph {

    public Piechart(IReport iReport) {
        super(iReport);
    }

    @Override
    void operation() {
        System.out.println("Pie chart accessed.");
        iReport.operationImpl();
    }
}

Advantages and disadvantages

Advantages of Bridge mode:

  • Separation of abstraction and implementation, strong scalability
  • Comply with the opening and closing principle
  • Comply with the principle of synthetic reuse
  • Its implementation details are transparent to customers

Disadvantages: because the aggregation relationship is based on the abstraction layer, developers are required to design and program for abstraction, and can correctly identify two independent changing dimensions in the system, which increases the difficulty of system understanding and design.

Application scenario

When a class has two or more change dimensions, the use of bridging mode can decouple these change dimensions and stabilize the high-level code architecture.

The bridging mode is generally applicable to the following scenarios:

  1. When a class has two independently changing dimensions and both dimensions need to be extended;
  2. When a system does not want to use inheritance or the number of system classes increases sharply due to multi-level inheritance;
  3. When a system needs to add more flexibility between the abstract and concrete roles of components.

A common usage scenario for bridging patterns is substitution inheritance. We know that inheritance has many advantages, such as abstraction, encapsulation, polymorphism, etc. the parent class encapsulates commonality and the subclass implements characteristics. Inheritance can well realize the function of code reuse (encapsulation), but this is also a major disadvantage of inheritance.

Because the methods owned by the parent class will be inherited by the child class, whether the child class needs it or not, this shows that inheritance is highly intrusive (the parent code invades the child class) and will cause the child class to be bloated. Therefore, in design patterns, there is a principle that composition / aggregation is preferred over inheritance.

Extension of bridging mode

In software development, sometimes Bridge mode can be combined with Adapter mode Combined use. When the interface of the implementation role of the Bridge mode is inconsistent with the interface of the existing class, an adapter can be defined between them to connect them. Its structure diagram is as follows:

Application in source code

JDBC Driver
......

Posted by grigori on Sun, 07 Nov 2021 11:28:12 -0800