Java simple design pattern

Posted by austingecko on Mon, 03 Jan 2022 12:28:06 +0100

Java simple design pattern

The realization of design pattern is to make it easier to maintain, more concise, high decoupling, reduce memory consumption and other excellent characteristics.

1. Singleton design pattern

Singleton design pattern: ensure that a class has only one instance, and provide a global access point to access it, so as to save the scene that tool classes constantly create objects and consume memory when they are used frequently.

It is generally used in frequently called tool classes.

1. Single example design mode steps:

  • Construction method Privatization (cannot be called outside the class, only this class)
  • Declare static objects of this class
  • Provide a static method to get the object instance (call the class name instead of new to create the object, and create the instance object only once)

2. Two design modes:

  • Hungry Chinese style: after the class is loaded, the object is created immediately and released at the end of the program. Long memory consumption and high efficiency.
  • Lazy: after the class is loaded and the corresponding method is called, the object is created and released at the end of the program. Short memory occupation time and low efficiency. (recommended)

Examples are as follows:

Examples involving static areas.

package com.singleton;

public class Singleton01 {
    public static void main(String[] args) {
        SingletonTest01 s1 = SingletonTest01.getInstance();
        s1.printTest();
        SingletonTest01 s12 = SingletonTest01.getInstance();
        //s1 and s12 are the same instance
        System.out.println(s1==s12);//Compare memory addresses and return true

        SingletonTest02 s2 = SingletonTest02.getInstance();
        s2.printTest();
    }
}

//Hungry Han style
class SingletonTest01 {
    //This class object is created immediately after the call
    private static SingletonTest01 s = new SingletonTest01();//Create this class object

    public SingletonTest01() {}

    public static SingletonTest01 getInstance() {
        return s;
    }

    public void printTest() {
        System.out.println("Hungry Han single case design mode");
    }
}

//Lazy style
class SingletonTest02 {
    private static SingletonTest02 s;//Declaration reference

    public SingletonTest02() {}

    public static SingletonTest02 getInstance() {
        if (s == null) {
            return new SingletonTest02();
        }
        return s;
    }

    public void printTest() {
        System.out.println("Lazy singleton design pattern");
    }
}

2. Template method design pattern

Template method pattern: defines the skeleton of an algorithm in operation, and delays the implementation of some variable parts to subclasses. The subclass can redefine some specific steps of an algorithm without changing the structure of the algorithm.

The essence is to define an algorithm framework, that is, to abstract the public part.

Examples are as follows:

This is an example of an abstract class. In the teacher student management system, login verification is required to verify whether it is an administrator. Therefore, the verification operation can be abstracted into a template, while the teacher management class and student management class only care about the operation of teachers or students, not the verification operation, making the code more concise.

package com.singleton;

public class Singleton02 {
    public static void main(String[] args) {
        StudentManager sm = new StudentManager();
        //Subclasses can call public methods in the parent class
        sm.action("admin", "add");//Perform student addition
        sm.action("student", "add");//You do not have permission to access, please contact the administrator
    }
}

abstract class BaseManager {
    public void action(String name, String method) {
        //Verify that you are logged in as an administrator
        if ("admin".equals(name)) {
            //If yes, execute the corresponding method
            execute(method);
        } else {
            System.out.println("You do not have permission to access, please contact the administrator");
        }
    }

    //The specific implementation process is handed over to the subclass
    abstract public void execute(String name);
}

//For student management, you need to log in and verify whether you are an administrator before performing other operations
class StudentManager extends BaseManager {
    //Verify the login operation in a special class, and the class can inherit

    //You must perform the following actions after logging in
    @Override
    public void execute(String method) {
        if ("add".equals(method)) {
            System.out.println("Perform student addition");
        } else if ("del".equals(method)) {
            System.out.println("Delete student");
        } else {
            System.out.println("Perform other student actions");
        }
    }
}

//For the teacher management class, you need to log in to verify whether you are an administrator before performing other operations
class TeacherManager extends BaseManager {
    //You must perform the following actions after logging in
    @Override
    public void execute(String method) {
        if ("add".equals(method)) {
            System.out.println("Perform teacher addition");
        } else if ("del".equals(method)) {
            System.out.println("Perform teacher deletion");
        } else {
            System.out.println("Perform other operations");
        }
    }
}

3. Strategy design pattern

Policy design pattern: it defines a series of algorithms, encapsulates each algorithm and can replace each other. The policy pattern allows the algorithm to change independently from the customer application using it.

An interface has multiple implementations. Different implementations are encapsulated independently, and can be replaced with each other according to runtime requirements. Maintainability is enhanced, and the new interface will not affect other implementation classes.

Examples are as follows:

This is an interface application example. The function of saving on demand may be to save to database, network or disk.

package com.singleton;

public class Singleton03 {
    public static void main(String[] args) {
        BaseService bs = new UserService();
        bs.setISave(new FileSave());
        bs.saveData("Hello");
        
        bs.setISave(new NetSave());
        bs.saveData("Hello");
    }
}

//Define the save interface, only implement specific functions, and leave the rest to the management class
interface ISave {
    void save(String data);
}

//Disk save mode
class FileSave implements ISave {
    @Override
    public void save(String data) {
        System.out.println("Disk save" + data);
    }
}

//Network saving method
class NetSave implements ISave {
    @Override
    public void save(String data) {
        System.out.println("Network save" + data);
    }
}

//Save method management class
abstract class BaseService {
    private ISave iSave;

    public void setISave(ISave iSave) {
        this.iSave = iSave;
    }

    public void saveData(String data) {
        System.out.println("Check data validity");
        iSave.save(data);
        System.out.println("Data saved successfully");
    }
}

class UserService extends BaseService {
	//Self definition
}

4. Simple factory design pattern

Simple factory design pattern: a factory object determines which product class instance to create.

The essence is to obtain objects through factory classes rather than directly create objects. The advantage of this is that it does not depend on the specific object model to be created, which has achieved the purpose of decoupling.

Simple factory mode design steps:

  • Establish interface
  • Different implementation methods for establishing interfaces
  • Create factory classes to create instance objects that implement different methods

Examples are as follows:

A mobile computer use case uses the factory to create a subclass object that implements the interface.

package com.singleton;

public class Singleton04 {
    public static void main(String[] args) {
        //Static methods can be called directly (class name. Method)
        Product product = ProductFactory.getProduct("phone");
        product.work();//The phone starts working
        Product product2 = ProductFactory.getProduct("computer");
        product2.work();//The computer starts working
    }
}

//Factory class, which is used to create objects to reduce code coupling
class ProductFactory {
    public static Product getProduct(String name) {
        if ("phone".equals(name)) {
            return new Phone();
        } else if ("computer".equals(name)) {
            return new Computer();
        } else {
            return null;
        }
    }
}

interface Product {
    void work();
}

class Phone implements Product {
    @Override
    public void work() {
        System.out.println("The phone starts working");
    }
}

class Computer implements Product {
    @Override
    public void work() {
        System.out.println("The computer starts working");
    }
}

5. Static proxy mode

Proxy mode: provides a proxy for other objects to control access to this object. That is, the representative of "real object", which introduces a certain degree of indirectness when accessing the object, and can add a variety of purposes.

Proxy mode is to control the access to the target object through the proxy object. For example: a bucket of water, we want water, but without a bucket, there is no water, so we must have a bucket.

Static proxy mode steps:

  • Establish interface
  • Establish interface implementation class
  • Establish an interface proxy class (the specific interface instance object is passed in this class)

Examples are as follows:

package com.singleton;

public class Singleton05 {
    public static void main(String[] args) {
        Action userAction = new UerAction();
        ActionProxy actionProxy = new ActionProxy(userAction);
        actionProxy.doAction();
    }
}

//Service interface
interface Action {
    void doAction();
}

//Interface object proxy class
class ActionProxy implements Action {
    private Action target;//Proxy object

    public ActionProxy(Action target) {
        this.target = target;
    }

    @Override
    //Proxy controls access to objects
    public void doAction() {
        //Record current time
        long startTime = System.currentTimeMillis();
        target.doAction();
        long endTime = System.currentTimeMillis();
        System.out.println("Total time" + (endTime - startTime) + "millisecond");
    }
}

//Concrete implementation class
class UerAction implements Action {
    @Override
    public void doAction() {
        //The number of cycles is large and the program time is long
        for (int i = 0; i < 100000000; i++) {}
        System.out.println("User starts working");
    }
}

6. Adapter design pattern

Adapter pattern: convert the interface of a class into another interface desired by the user. The adapter pattern allows classes that cannot work together because of interface incompatibility to work together.

Examples are as follows:

The two interfaces realize adaptation.

package com.singleton;

public class Singleton06 {
    public static void main(String[] args) {
        PowerA powerA = new PowerAImpl();
//        work(powerA);

        PowerBImpl powerB = new PowerBImpl();
        Adapter adapter = new Adapter(powerB);
        work(adapter);
    }

    public static void work(PowerA a) {
        a.insert();
    }
}

//Adapter. In this method, the B interface is transformed, implicitly passed into the A interface, and the method in the A interface is rewritten.
//It is the implementation class of A interface
class Adapter implements PowerA {
    private PowerB powerB;

    public Adapter(PowerB powerB) {
        this.powerB = powerB;
    }

    @Override
    public void insert() {
        powerB.connect();
    }
}

interface PowerB {
    void connect();
}

class PowerBImpl implements PowerB {
    @Override
    public void connect() {
        System.out.println("B start-up");
    }
}

interface PowerA {
    void insert();
}

class PowerAImpl implements PowerA {
    @Override
    public void insert() {
        System.out.println("A start-up");
    }
}

OO design principles:

  • Interface oriented programming (Abstract oriented programming)
  • Package change
  • Use more combination and less inheritance
  • It is closed for modification and open for extension

Finally, if you have more interest in learning, you can browse my website Personal blog.

Topics: Java Design Pattern Back-end JavaSE