Several common design patterns in Java

Singleton mode

Simply put, in an application, there is only one instance object of a class. You can't go to new because the constructors are decorated by private. Generally, they get their instances through getInstance().

 

The return value of getInstance() is a reference to an object, not a new instance, so don't misunderstand it as multiple objects. It's easy to implement the singleton mode. Let's go to demo

 

public class Singleton {

private static Singleton singleton;

private Singleton() {
}

public static Singleton getInstance() {
 if (singleton == null) {
  singleton = new Singleton();
 }
 return singleton;
}
}

 

 

 

According to my habit, I wish I could write all the comments. I'm afraid you can't understand it, but this code is too simple, so I didn't write any comments. If you can't understand these lines of code, you can wash and sleep, and read my blog when you wake up.

 

The above is the most basic writing method, also known as lazy writing (thread is not safe). Next, I will publish several writing methods of singleton mode:

 

Lazy writing (thread safe)

 

public class Singleton {  
   private static Singleton instance;  
   private Singleton (){}  
   public static synchronized Singleton getInstance() {  
   if (instance == null) {  
       instance = new Singleton();  
   }  
   return instance;  
   }  
}

 

Hungry Han style writing

 

public class Singleton {  
   private static Singleton instance = new Singleton();  
   private Singleton (){}  
   public static Singleton getInstance() {  
   return instance;  
   }  
}

 

Static inner class

 

public class Singleton {  
   private static class SingletonHolder {  
   private static final Singleton INSTANCE = new Singleton();  
   }  
   private Singleton (){}  
   public static final Singleton getInstance() {  
   return SingletonHolder.INSTANCE;  
   }  
}

enumeration

 

public enum Singleton {  
   INSTANCE;  
   public void whateverMethod() {  
   }  
}

 

This method is advocated by Josh Bloch, author of Effective Java. It can not only avoid the problem of multithreading synchronization, but also prevent deserialization from re creating new objects. It's a very strong barrier. However, I think it's strange to write in this way because of the enum feature added in 1.5.

Double check lock

 

public class Singleton {  
   private volatile static Singleton singleton;  
   private Singleton (){}  
   public static Singleton getSingleton() {  
   if (singleton == null) {  
       synchronized (Singleton.class) {  
       if (singleton == null) {  
           singleton = new Singleton();  
       }  
       }  
   }  
   return singleton;  
   }  
}

 

 

Conclusion: I prefer static internal style and starved Chinese style. In fact, these two styles can cope with the vast majority of situations. Other writing methods can also be selected, mainly depending on business needs.

 

 

Observer mode

 

When the state of an object changes, all objects that depend on it are notified and updated automatically.

 

 

Observer pattern UML diagram

 

People who can't understand the picture come here with a small bench and give you a chestnut: suppose there are three people, Xiaomei (female, 22), Xiaowang and Xiaoli. Xiaomei is very beautiful. Xiaowang and Xiaoli are two procedural apes. They always pay attention to Xiaomei's every move. One day, Xiaomei said, "who will play games with me?" This sentence was heard by Xiao Wang and Xiao Li, but they were very happy. After a while, Xiao Wang rushed to Xiao Mei's door. Here, Xiao Mei is the observed, Xiao Wang and Xiao Li are the observer, and the observed sent a message, and then the observers processed it accordingly. See the Code:

 

public interface Person {
   //Xiaowang and Xiaoli can receive messages from Xiaomei through this interface
   void getMessage(String s);
}

l

This interface is equivalent to the phone numbers of Xiaowang and Xiaoli. Xiaomei will call getMessage when she sends the notice. Calling is to call the interface. It doesn't matter if you don't understand it. First look down

 

public class LaoWang implements Person {

   private String name = "Xiao Wang";

   public LaoWang() {
   }

   @Override
   public void getMessage(String s) {
       System.out.println(name + "I received a call from Xiaomei, the content of which is:" + s);
   }

}

public class LaoLi implements Person {

   private String name = "petty thief";

   public LaoLi() {
   }

   @Override
   public void getMessage(String s) {
       System.out.println(name + "I received a call from Xiaomei, the content of which is:->" + s);
   }

}

 

The code is very simple. Let's take a look at Xiaomei's code:

 

public class XiaoMei {
   List<Person> list = new ArrayList<Person>();
    public XiaoMei(){
    }

    public void addPerson(Person person){
        list.add(person);
    }

    //ergodic list,Send your notice to all those who secretly love you
    public void notifyPerson() {
        for(Person person:list){
            person.getMessage("Come here. Whoever comes first can play games with me!");
        }
    }
}

 

Let's write a test class to see if the result is right

 

public class Test {
   public static void main(String[] args) {

       XiaoMei xiao_mei = new XiaoMei();
       LaoWang lao_wang = new LaoWang();
       LaoLi lao_li = new LaoLi();

       //Xiao Wang and Xiao Li have registered with Xiao Mei
       xiao_mei.addPerson(lao_wang);
       xiao_mei.addPerson(lao_li);

       //Xiaomei sends a notice to Xiaowang and Xiaoli
       xiao_mei.notifyPerson();
   }
}

 

Perfect ~

 

 

Decorator mode

The existing business logic is further encapsulated to add additional functions. For example, the IO flow in Java uses the decorator mode. When users use it, they can assemble it at will to achieve the desired effect. For example, I want to eat a sandwich. First of all, I need a big sausage. I like to eat cream. Add a little cream on the sausage, put some vegetables on it, and then use two pieces of bread to sandwich it. It's a delicious lunch, nutritious and healthy. (ps: I don't know where there are delicious sandwiches in Shanghai, please recommend ~) so how should we write the code? First of all, we need to write a Food class so that all other foods can inherit this class. Look at the code:

 

public class Food {

   private String food_name;

   public Food() {
   }

   public Food(String food_name) {
       this.food_name = food_name;
   }

   public String make() {
       return food_name;
   };
}

 

The code is very simple, I won't explain it, and then we write several subclasses to inherit it:

 

//Bread
public class Bread extends Food {

   private Food basic_food;

   public Bread(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       return basic_food.make()+"+bread";
   }
}

//Creams 
public class Cream extends Food {

   private Food basic_food;

   public Cream(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       return basic_food.make()+"+cream";
   }
}

//Vegetables
public class Vegetable extends Food {

   private Food basic_food;

   public Vegetable(Food basic_food) {
       this.basic_food = basic_food;
   }

   public String make() {
       return basic_food.make()+"+Vegetables";
   }

}

 

These classes are almost the same. The constructor passes in a parameter of Food type, and then adds some logic to the make method. If you still can't understand why you write this, don't worry. Take a look at how my Test class is written, and you will see it

 

public class Test {
   public static void main(String[] args) {
       Food food = new Bread(new Vegetable(new Cream(new Food("Sausage"))));
       System.out.println(food.make());
   }
}

 

See, layer by layer, we can see from the inside out: I have a new sausage in the innermost part, I have a layer of cream outside the sausage, and I have added a layer of vegetables outside the cream. What I put on the outermost part is bread. Isn't it very vivid? Ha ha ~ this design mode is almost the same as that in real life. Do you understand? Let's see the results

 

 

Operation results

 

A sandwich is ready

 

 

Adapter mode

Connect two completely different things together, like transformers in real life. Suppose that a mobile phone charger needs 20V, but the normal voltage is 220V. In this case, a transformer is needed to convert the voltage of 220V into 20V, so that the transformer connects 20V with the mobile phone.

public class Test {
   public static void main(String[] args) {
       Phone phone = new Phone();
       VoltageAdapter adapter = new VoltageAdapter();
       phone.setAdapter(adapter);
       phone.charge();
   }
}

// Mobile phones
class Phone {

   public static final int V = 220;// Normal voltage 220 v,Is a constant

   private VoltageAdapter adapter;

   // Charge
   public void charge() {
       adapter.changeVoltage();
   }

   public void setAdapter(VoltageAdapter adapter) {
       this.adapter = adapter;
   }
}

// transformer
class VoltageAdapter {
   // Function of changing voltage
   public void changeVoltage() {
       System.out.println("Charging...");
       System.out.println("Original voltage:" + Phone.V + "V");
       System.out.println("Voltage after transformer conversion:" + (Phone.V - 200) + "V");
   }
}

 

 

 

Factory mode

Simple factory pattern: an abstract interface, an implementation class of multiple abstract interfaces, and a factory class are used to instantiate the abstract interface

// Abstract product class
abstract class Car {
   public void run();

   public void stop();
}

// Concrete implementation class
class Benz implements Car {
   public void run() {
       System.out.println("Benz It's starting.....");
   }

   public void stop() {
       System.out.println("Benz Stop the car.....");
   }
}

class Ford implements Car {
   public void run() {
       System.out.println("Ford It's starting...");
   }

   public void stop() {
       System.out.println("Ford Stop the car....");
   }
}

// Factory
class Factory {
   public static Car getCarInstance(String type) {
       Car c = null;
       if ("Benz".equals(type)) {
           c = new Benz();
       }
       if ("Ford".equals(type)) {
           c = new Ford();
       }
       return c;
   }
}

public class Test {

   public static void main(String[] args) {
       Car c = Factory.getCarInstance("Benz");
       if (c != null) {
           c.run();
           c.stop();
       } else {
           System.out.println("I can't make such a car...");
       }

   }

}

 

//Factory method pattern: there are four roles: abstract factory pattern, concrete factory pattern, abstract product pattern and concrete product pattern. It is no longer a factory class to instantiate a specific product, but a subclass of an abstract factory to instantiate a product

 

// Abstract product role
public interface Moveable {
   void run();
}

// Specific product roles
public class Plane implements Moveable {
   @Override
   public void run() {
       System.out.println("plane....");
   }
}

public class Broom implements Moveable {
   @Override
   public void run() {
       System.out.println("broom.....");
   }
}

// Abstract factory
public abstract class VehicleFactory {
   abstract Moveable create();
}

// Specific plant
public class PlaneFactory extends VehicleFactory {
   public Moveable create() {
       return new Plane();
   }
}

public class BroomFactory extends VehicleFactory {
   public Moveable create() {
       return new Broom();
   }
}

// Test class
public class Test {
   public static void main(String[] args) {
       VehicleFactory factory = new BroomFactory();
       Moveable m = factory.create();
       m.run();
   }
}

 

Abstract factory mode: unlike factory method mode, factory in factory method mode only produces a single product, while factory in abstract factory mode produces multiple products

 

/Abstract factory class
public abstract class AbstractFactory {
   public abstract Vehicle createVehicle();
   public abstract Weapon createWeapon();
   public abstract Food createFood();
}
//Specific factory class, in which Food,Vehicle,Weapon It's an abstract class,
public class DefaultFactory extends AbstractFactory{
   @Override
   public Food createFood() {
       return new Apple();
   }
   @Override
   public Vehicle createVehicle() {
       return new Car();
   }
   @Override
   public Weapon createWeapon() {
       return new AK47();
   }
}
//Test class
public class Test {
   public static void main(String[] args) {
       AbstractFactory f = new DefaultFactory();
       Vehicle v = f.createVehicle();
       v.run();
       Weapon w = f.createWeapon();
       w.shoot();
       Food a = f.createFood();
       a.printName();
   }
}

 

 

proxy mode


There are two kinds, static agent and dynamic agent. Let's start with static agent. I won't talk about many theoretical things. Even if I talk about them, you can't understand them. What real role, abstract role, agent role, delegation role... I can't understand the mess. When I was learning the agent mode, I went to the Internet to search for a lot of information and open the links. Basically, I gave you a lot of analysis about the roles and theories. It seems very hard. If you don't believe me, you can go and have a look. I can't understand what they are talking about. Let's not talk about it in vain, just use the examples in life. (Note: I'm not denying theoretical knowledge here. I just think that sometimes theoretical knowledge is obscure and difficult to understand. People who like to challenge go to learn knowledge, not to challenge.)
When we get to a certain age, we are going to get married. It is a very troublesome thing to get married (including those who are urged to marry by their parents). Rich families may look for a MC to preside over the wedding, which seems lively and foreign. Now that the business of the wedding company is coming, we just need to give money, and the wedding company will help us arrange a whole set of wedding process. The whole process is like this: family urging marriage - > the ecliptic of marriage agreed by both men and women's families today - > find a reliable wedding company - > hold the wedding ceremony at the appointed time - > marriage is over
How does the wedding company plan to arrange the wedding program? What will the wedding company do after the wedding? We have no idea... Don't worry, it's not a black intermediary. We just need to give money to others, who will do a good job for us. So, the wedding company here is equivalent to an agent role. Now you know what an agent role is.





For code implementation, see:

 

//Proxy interface
public interface ProxyInterface {
//It's about getting married. If there are other things that need to be represented, such as eating, sleeping and going to the toilet, you can also write
void marry();
//Proxy meal(Let others eat your own food)
//void eat();
//Agency shit, own shit, let others pull it
//void shit();
}

 

In a civilized society, I will not write about acting for eating and shit. It will hurt the social decency and make it clear


OK, let's look at the code of the wedding company:

 

public class WeddingCompany implements ProxyInterface {

private ProxyInterface proxyInterface;

public WeddingCompany(ProxyInterface proxyInterface) {
 this.proxyInterface = proxyInterface;
}

@Override
public void marry() {
 System.out.println("We're from the wedding company");
 System.out.println("We are preparing for our wedding");
 System.out.println("Program rehearsal...");
 System.out.println("Gift purchase...");
 System.out.println("Division of labor...");
 System.out.println("It's time to get married");
 proxyInterface.marry();
 System.out.println("After marriage, we need to do follow-up processing. You can go home and our company will do the rest");
}

}

 

See? There are many things that wedding companies need to do. Let's look at the code of marriage family:

 

public class NormalHome implements ProxyInterface{

@Override
public void marry() {
 System.out.println("We're married~");
}

}

 

It's already obvious that marriage families only need to get married, and the wedding company should take care of everything. All the things before and after are done by the wedding company. It's said that the wedding company is very profitable now. That's the reason. There are many jobs to do. Can we not make money?


Take a look at the test class code:

 

public class Test {
public static void main(String[] args) {
 ProxyInterface proxyInterface = new WeddingCompany(new NormalHome());
 proxyInterface.marry();
}
}

 

The operation results are as follows:

Producer / consumer model

 

What is the producer / consumer model?

 

One module is responsible for generating data, which is processed by another module (the module here is generalized, which can be class, function, thread, process, etc.). The module that generates data is vividly called the producer, while the module that processes data is called the consumer. A buffer zone is added between the producer and the consumer, which is called the warehouse. The producer is responsible for entering the goods into the warehouse, and the consumer is responsible for taking the goods from the warehouse, which constitutes the producer consumer model. The structure diagram is as follows:

 

The producer consumer model has the following advantages:

1. Decoupling

Due to the existence of buffer, there is no direct dependence between producers and consumers, and the coupling degree is reduced.

2. Concurrent support

As producers and consumers are two independent concurrent entities, they are connected by buffer as a bridge. Producers only need to throw data into the buffer to continue to produce the next data, while consumers only need to get data from the buffer, so that they will not be blocked due to each other's processing speed.

3. Uneven free and busy support

The buffer has another benefit. If the speed of manufacturing data is fast or slow, the benefits of buffer are shown. When data manufacturing is fast, consumers have no time to process, and unprocessed data can be temporarily stored in the buffer. Wait for the manufacturer's manufacturing speed to slow down, and then the consumer will slowly dispose of it.

 

The producer consumer model should be exactly the "producer warehouse consumer" model, which follows the following rules:

1. The producer only produces when the warehouse is not full, and stops production when the warehouse is full.
2. Consumers can only consume when there are products in the warehouse, and wait when the warehouse is empty.
3. When consumers find that there is no product to consume in the warehouse, they will inform the producers to produce.
4. When producing consumable products, producers should inform waiting consumers to consume


This model will combine the wait, notify and notifyAll methods of java.lang.Object to achieve the above requirements. The example code is as follows:

Create so-called "warehouses" that are shared data areas (essentially: shared access)

//This class is (essentially: shared access) a shared data area
public class SyncStack {
    
    private String[]  str = new String[10];
    
    private int index;
    
    //For producers to call
    public synchronized void push(String sst){
        if(index == sst.length()){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.notify();//Wake up a single thread waiting on this object monitor 
        str[index] = sst;
        index++;
    }
    
    //For consumers  
    public synchronized String pop(){
        if(index == 0){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.notify();
        index--;
        String product = str[index];
        return product;
        
    }
    
    //Is to define a method that returns an array,Back to a String[]Quote  
    public String[] pro(){
        return str;
    }
}

Create producer:

public class Producter implements Runnable {
    
    private SyncStack stack;
    
    public Producter(SyncStack stack){
        this.stack = stack;
    }
    
    public void run(){
        for(int i = 0;i<stack.pro().length;i++){
            String producter = "product" + i;
            stack.push(producter);
            System.out.println("Produced:" + producter);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
    }
}

Create consumer:

public class Consumer implements Runnable {
    
    private SyncStack stack;
    
    public Consumer(SyncStack stack){
        this.stack = stack;
    }
    public void run(){
        for(int i=0;i<stack.pro().length;i++){
            String consumer = stack.pop();
            System.out.println("Consumed:" + consumer );
            
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Test class:

public class TestDeam {

    public static void main(String[] args) {
        SyncStack stack = new SyncStack();  
        Consumer p = new Consumer(stack);  
        Producter c = new Producter(stack);  
             
        new Thread(p).start();  
        new Thread(c).start(); 

    }
}

Test results:

Produced: product 0
Consumed: product 0
Produced: Product 1
Produced: product 2
Consumed: product 2
Produced: product 3
Consumed: product 3
Produced: product 4
Produced: product 5
Produced: product 6
Consumed: product 5
Produced: product 7
Consumed: product 6
Consumed: product 7
Produced: product 8
Produced: product 9
Consumed: product 8
Consumed: product 9
Consumed: product 4
Consumed: Product 1

(end)

Tags: Java Mobile REST

Posted on Sun, 03 May 2020 17:34:39 -0400 by neo_phyte