Design pattern s are a set of repetitive, well-known, categorized, code design experiences.
There are three types of design patterns, 23 of which are:
- Creative mode: Singleton mode,Abstract Factory Mode,Builder pattern,Factory Mode,Prototype mode.
- Structural pattern: Adapter mode,Bridge mode,Decoration Mode,Combination mode,Appearance Mode,Hedonic mode,proxy pattern.
- Behavioral patterns: template method,Command mode,Iterator mode,Observer mode,Intermediator mode,Memento,Interpreter,State mode,Policy Mode,Responsibility chain model,Visitor.
GitHub: youlookwhat/DesignPattern
Refer to articles written by Hong Yang, Newbie Tutorial, etc.If there are any errors, please correct them. If there are any infringements, please contact me to delete them.
Blog Catalogue:
-
1. Design Patterns Observer Patterns Take WeChat Public Service as an Example
-
7. Design Mode Decorator Pattern brings you back to the legend
-
11. Design pattern Builder pattern Take building a car and buying a car as an example
-
12. Prototype Pattern: An example of getting multiple shapes
-
13. Flyweight Pattern: An example of randomly getting multiple shapes
-
14. Design Mode Proxy Pattern Take getting pictures on disk as an example
-
15. Design Mode Bridge Pattern takes drawing circles of different colors as an example
-
16. Composite Pattern to create and print a hierarchy of employees as an example
-
17. Design Mode Iterator Pattern as an example of printing names using an iterator
-
18. Design Mode Mediator Pattern: A Public Chat Room Example
-
19. Design Mode Memento Pattern as an example of using a memo
-
20. Interpreter Pattern: An example of interpreting a sentence
-
21. Design Mode Chain of Responsibility Pattern Example of Print Log in Android Studio
-
22. Design Mode Visitor Pattern Example of displaying components of a computer
Source Code
Project Picture
Pattern Analysis
1. Observer mode
Defines a one-to-many dependency between objects so that when an object changes, all its dependents are notified and updated automatically.
-
For JDK or Andorid, there are many places where observer mode is implemented, such as XXXView.addXXXListener, of course XXXView.setOnXXXListener is not necessarily observer mode, because observer mode is a one-to-many relationship, and setXXXListener is a one-to-one relationship, which should be called callback.
-
Thematic interface: Subject.java ;
/** * Register an observer */ public void registerObserver(Observer observer); /** * Remove an observer */ public void removeObserver(Observer observer); /** * Notify all observers */ public void notifyObservers();
-
Implementation class for 3D service number: ObjectFor3D.java
@Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { int index = observers.indexOf(observer); if (index >= 0) { observers.remove(index); } } @Override public void notifyObservers() { for (Observer observer : observers) { observer.update(msg); } } /** * Topic Update Information */ public void setMsg(String msg) { this.msg = msg; notifyObservers(); }
-
All observers need to implement this interface: Observer.java
public ObserverUser1(Subject subject) { subject.registerObserver(this); } @Override public void update(String msg) { Log.e("-----ObserverUser1 ", "Get 3 D number:" + msg + ", I want to write it down."); }
-
Last test: ObserverActivity.java
// Create Service Number objectFor3D = new ObjectFor3D(); // Create two subscribers observerUser1 = new ObserverUser1(objectFor3D); observerUser2 = new ObserverUser2(objectFor3D); // Two observers, sending two messages objectFor3D.setMsg("201610121 3 D be entitled as:127"); objectFor3D.setMsg("20161022 3 D be entitled as:000");
2. Factory Mode
To briefly list the families of this pattern:
-
1. Static Factory Mode
- This is the most common, auxiliary class in a project, TextUtil.isEmpty, etc., class + static method.
-
2. Simple Factory Mode (Buy meat clips in stores)
- Definition: Create instances of other classes by specifically defining one class. The instances created usually have a common parent class.
- Create meat clips directly according to type: SimpleRoujiaMoFactory.java
public RoujiaMo creatRoujiaMo(String type) { RoujiaMo roujiaMo = null; switch (type) { case "Suan": roujiaMo = new ZSuanRoujiaMo(); break; case "La": roujiaMo = new ZLaRoujiaMo(); break; case "Tian": roujiaMo = new ZTianRoujiaMo(); break; default:// Default to sour meat bun roujiaMo = new ZSuanRoujiaMo(); break; } return roujiaMo; }
-
3. Factory method mode (opening a branch)
- Definition: Defines an interface for creating objects, but subclasses determine which class to instantiate.The factory method pattern defers class instantiation to subclasses.
- Definition of comparison:
- 1. An interface for creating objects is defined: public abstract RouJiaMo sellRoujiaMo(String type);
- 2. The instantiated classes are determined by the subclasses. You can see that our buns are generated by the subclasses.
-
Provides an abstract way to create a meat clip bun store: RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo(String type);
-
Implement abstract methods specifically: XianRoujiaMoStore.java
-
Branches still use the simple factory model: XianSimpleRoujiaMoFactory.java
-
4. Abstract Factory Mode (using officially supplied raw materials)
- Definition: Provides an interface for creating a family of related or dependent objects without explicitly specifying a specific class.
- Definition of comparison:
- 1. Provide an interface: public interface RouJiaMoYLFactroy
- 2. Family public Meat createMeat();public YuanLiao createYuanliao(); our interface is used to create a series of raw materials.
- Create an interface factory to supply raw materials: RoujiaMoYLFactory.java
- Each branch implements interfaces to complete the supply of raw materials: XianRoujiaMoYLFoctory.java
- When preparing, use official ingredients: RoujiaMo.java
/** * Dead work */ public void prepare(RoujiaMoYLFactory roujiaMoYLFactory) { Meet meet = roujiaMoYLFactory.creatMeet(); YuanLiao yuanLiao = roujiaMoYLFactory.creatYuanLiao(); Log.e("---RoujiaMo:", "Use official ingredients ---" + name + ": Kneading dough-Minced meat-Complete Preparations yuanLiao:"+meet+"yuanLiao:"+yuanLiao); }
3. Single Case Design Mode
Singleton mode is designed to avoid wasting resources by creating multiple instances, and multiple instances are prone to errors due to multiple calls. Using singleton mode ensures that there is only one instance in the entire application.
-
Definition: Only three steps are required to ensure the uniqueness of the object
- (1) Do not allow other programs to use new objects
- (2) Create objects in this class
- (3) Provide a method for other programs to obtain the object
-
Definition of comparison:
- (1) Privateize the constructor for this class
- (2) Create an object of this class from new
- (3) Define a public method that returns the objects created in that class
-
Hungry Han style [available]: SingletonEHan.java
-
Lazy man style [recommended for double check locks]: SingletonLanHan.java
private SingletonLanHan() {} private static SingletonLanHan singletonLanHanFour; public static SingletonLanHan getSingletonLanHanFour() { if (singletonLanHanFour == null) { synchronized (SingletonLanHan.class) { if (singletonLanHanFour == null) { singletonLanHanFour = new SingletonLanHan(); } } } return singletonLanHanFour; }
- Internal class [recommended]: SingletonIn.java
- Enumeration [Recommended]: SingletonEnum.java
4. Policy Patterns
Strategy mode: A family of algorithms is defined and encapsulated so that they can be replaced with each other. This mode makes the algorithm change independent of the customers using the algorithm.
- Take creating game roles as an example:
- Summary:
- 1. Encapsulate changes (encapsulate potentially changing code)
- 2. Use combinations more than inheritance (we use combinations to set up algorithms for our clients)
- 3. Programming for interfaces, not for implementations (Role class design is entirely role-specific, not related to skill achievement)
- Last test: Create roles:
RoleA roleA = new RoleA("---A"); roleA.setiDisplayBehavior(new DisplayYZ()) .setiAttackBehavior(new AttackXL()) .setiDefendBehavior(new DefendTMS()) .setiRunBehavior(new RunJCTQ()); roleA.display();// A look roleA.attack();// attack roleA.run();// escape roleA.defend();// defense
5. Adapter mode
Definition: Converts the interface of one class to another that the client expects, and the adapter allows classes that are incompatible with the original interface to cooperate with each other.That's a good definition. An adapter's function is to convert one interface into another.
-
Take the charger as an example: mobile phone chargers are generally around 5V, our home AC voltage is 220V, so mobile phone charging requires an adapter (pressure reducer)
-
A mobile phone: Mobile.java
-
The phone relies on an interface that provides 5V voltage: V5Power.java
-
We have 220V home AC: V220Power.java
-
Adapter for 220V to 5V: V5PowerAdapter.java
-
Last test: power your phone:
Mobile mobile = new Mobile(); V5Power v5Power = new V5PowerAdapter(new V200Power()); mobile.inputPower(v5Power);
6. Command mode
Definition: Encapsulate a Request as an object to parameterize other objects using different requests, queues, or logs.Command mode also supports undoable operations.(simplification: encapsulate the request as an object and decouple the action requestor from the action executor.)
- Requirements: Recently, smart home appliances are hot. Assuming there are TV, computer, lamp and other home appliances now, you need to make a remote control to control the switches of all home appliances. You need to make the functions corresponding to each button personalized for users, and have a very strong scalability for newly purchased home appliances.
- 1. API for home appliances: Door.java
- 2. Encapsulate commands into classes:
- Unified command interface: Command.java
- Household appliances implement this interface: DoorOpenCommand.java
- 3. Remote control: ControlPanel.java
- 4. Define a command that does a series of things: QuickCommand.java
QuickCommand quickCloseCommand = new QuickCommand(new Command[]{new LightOffCommand(light), new ComputerOffCommand(computer), new DoorCloseCommand(door)}); controlPanel.setCommands(6, quickOpenCommand); controlPanel.keyPressed(6);
- 5. Remote control panel execution: CommandActivity.java
controlPanel.setCommands(0, new DoorOpenCommand(door));// Open the door controlPanel.keyPressed(0);
7. Decorator Mode
Decorator mode: To extend functionality, the decorator provides a more flexible alternative to integration, dynamically attaching responsibility to the object.
-
Let's start with a brief description of where the Decorator mode works. When we have designed a class, we need to add some auxiliary functions to it and don't want to change the code of this class. It's time for the Decorator mode to take on its grandeur.There is also a principle that classes should be open to extensions and closed to modifications.
-
Requirements: Design game equipment systems, basic requirements, to be able to calculate the attack power and description of each kind of equipment after various gems are inlaid:
-
1. Superclass of equipment: IEquip.java
-
2. Implementation classes of each equipment:
- eg: Implementation class of the weapon: ArmEquip.java
-
3. Superclass of ornaments (ornaments also belong to equipment): IEquipDecorator.java
-
4. Implementation class of ornaments:
- eg: Implementation class for sapphire (cumulative): BlueGemDecorator.java
-
5. Final test: Compute attack power and view description:
Log.e("---", "A mosaic of 2 rubies,1 Sapphire boots: "); IEquip iEquip = new RedGemDecotator(new RedGemDecotator(new BlueGemDecotator(new ShoeEquip()))); Log.e("---", "Aggressivity:" + iEquip.caculateAttack()); Log.e("---", "Description:" + iEquip.description());
8. Appearance Mode
Definition: Provides a unified interface for accessing a group of interfaces in a subsystem. The appearance defines a high-level interface to make the subsystem easier to use.In fact, to facilitate the use of customers, a group of operations, encapsulated into a method.
-
Demand: I prefer to watch movies, so I bought a projector, computer, audio, designed room lights, bought a popcorn machine, and then when I want to see a movie, I need one click to see it and one click to turn it off.
-
Switching and other operations for each device class:
-
eg: Popcorn maker: PopcornPopper.java
-
Cinema category: HomeTheaterFacade.java
/** * One-click Viewing */ public void watchMovie() { computer.on(); light.down(); popcornPopper.on(); popcornPopper.makePopcorn(); projector.on(); projector.open(); player.on(); player.make3DListener(); }
-
Last test: One-click viewing:
new HomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();
9. Template Method Mode
Definition: Defines the framework of an algorithm, delays some steps to subclasses, and the template method allows subclasses to redefine the steps of the algorithm without changing the structure of the algorithm.
-
Requirements: A brief description: The company has program apes, testing, HR, project managers, etc., below uses the template method mode to record the work of all personnel
-
Three types of roles in the template method pattern
-
1. Concrete Method
-
2. Abstract Method
-
3. Hook Method
-
Superclass of workers: Worker.java
// Specific methods public final void workOneDay() { Log.e("workOneDay", "-----------------work start----------------"); enterCompany(); work(); exitCompany(); Log.e("workOneDay", "-----------------work end----------------"); } // Working abstraction methods public abstract void work(); // Hook Method public boolean isNeedPrintDate() { return false; } private void exitCompany() { if (isNeedPrintDate()) { Log.e("exitCompany", "---" + new Date().toLocaleString() + "--->"); } Log.e("exitCompany", name + "---Leave the company"); }
-
Programmers implement classes (know the time): ITWorker.java
/** * Override this method of the parent class so that you can see the departure time */ @Override public boolean isNeedPrintDate() { return true; }
-
Last test:
-
View the work of all people:
QAWorker qaWorker = new QAWorker("Tester"); qaWorker(); HRWorker hrWorker = new HRWorker("Sister Lily"); hrWorker.workOneDay(); ...
-
See when the ape left the company:
ITWorker itWorker = new ITWorker("jingbin"); itWorker.workOneDay();
-
10. State Mode
Definition: Allows an object to change its behavior when its internal state changes, as if the object had modified its class.
-
The definition is blurred again, so when an object's internal state changes, its behavior changes with the change of state, which seems to reinitialize a similar one.
-
Requirements: vending machine as an example (with coined, non-coined status and coined, coined, etc.)
-
Initial implementation of vending machines to be improved: VendingMachine.java
-
Improved vending machine (more scalable): VendingMachineBetter.java
// Deposit money public void insertMoney() { currentState.insertMoney(); } // Return money public void backMoney() { currentState.backMoney(); } // Rotate Crank public void turnCrank() { currentState.turnCrank(); if (currentState == soldState || currentState == winnerState) { currentState.dispense();//Two cases will ship } } // Export Goods public void dispense() { Log.e("VendingMachineBetter", "---Send out a commodity"); if (count > 0) { count--; } } // Set corresponding state public void setState(State state) { this.currentState = state; }
-
State interface: State.java
-
Interface implementation classes for corresponding states:
- eg: Winning status: WinnerState.java
- eg: Sale Status: SoldState.java
-
Improved vending machine test:
// Initialize the vending machine with 3 items in it VendingMachineBetter machineBetter = new VendingMachineBetter(3); machineBetter.insertMoney(); machineBetter.turnCrank();
11. Builder Mode
Construction mode is the creative mode of the object.The construction mode can separate the internal representation of a product from the production process of the product, thus enabling a construction process to produce product objects with different internal representations.
-
Requirements: Users go to the car store to buy a car.
-
Analysis: Car stores extract cars based on each user's needs
-
Builder superclass: Builder
public abstract class Builder { public abstract void setPart(String name, String type); public abstract Product getProduct(); }
-
Builder corresponding implementation class: ConcreteBuilder
public class ConcreteBuilder extends Builder { private Product product = new Product(); @Override public void setPart(String name, String type) { product.setName(name); product.setType(type); } @Override public Product getProduct() { return product; } }
-
Shopowner Director Take Car:
// Shopowner Director director = new Director(); // Get a BMW car, internal implementation of extracting BMW car details Product product = director.getBProduct(); // Show car information product.showProduct();
12. Prototype mode
Prototype mode is used to create duplicate objects while maintaining performance.This type of design pattern is creative and provides the best way to create objects.
This pattern implements a prototype interface for creating a clone of the current object.This pattern is used when creating objects directly is expensive.For example, an object needs to be created after a costly database operation.We can reduce database calls by caching the object, returning its clone on the next request, and updating the database as needed.
There are four steps to get multiple shapes, for example:
-
1. Create an abstract class that implements the Cloneable interface. Shape(implements Cloneable)
public abstract class Shape implements Cloneable { private String id; protected String type; public abstract void draw(); public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public Object clone() { Object object = null; try { object = super.clone(); } catch (CloneNotSupportedException e) { Log.e("--", e.getMessage()); } return object; } }
-
2. Create entity classes that extend the abstract classes above. Circle,Rectangle,Square
public class Circle extends Shape { public Circle() { type = "Circle"; } @Override public void draw() { Log.e("---", "Inside Circle::draw() method."); } }
-
3. Create a class, get entity classes from the database, and store them in a Hashtable. ShapeCache
public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>(); public static Shape getShape(String shapeId) { Shape shapeCache = shapeMap.get(shapeId); return (Shape) shapeCache.clone(); } // Run a database query on each shape and create it // shapeMap.put(shapeKey, shape); // For example, we want to add three shapes public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(), circle); Rectangle rectangle = new Rectangle(); rectangle.setId("2"); shapeMap.put(rectangle.getId(), rectangle); Square square = new Square(); square.setId("3"); shapeMap.put(square.getId(), square); } }
-
4. Use the ShapeCache class to obtain clones of shapes stored in Hashtable.
// Use the ShapeCache class to get a clone of the shape stored in Hashtable. ShapeCache.loadCache(); Shape shapeCache1 = ShapeCache.getShape("1"); Shape shapeCache2 = ShapeCache.getShape("2"); Shape shapeCache3 = ShapeCache.getShape("3");
13. Enjoyment mode
Mainly used to reduce the number of objects created to reduce memory consumption and improve performance.This type of design pattern is structured and provides a way to reduce the number of objects and improve the object structure required for application.
The enjoyment mode attempts to reuse an existing object of the same type, and if no matching object is found, a new object is created.We'll demonstrate this pattern by creating five objects to draw 20 circles distributed in different locations.Since only five colors are available, the color attribute is used to examine existing Circle objects.
- The main solution: When there are a large number of objects, memory overflow may occur. We abstract the common parts of them, and if there is the same business request, return the objects that already exist in memory directly to avoid re-creation.
Take random shape acquisition as an example, which is divided into four steps:
-
1. Create an interface.
public interface Shape { void draw(); }
-
2. Create entity classes that implement interfaces.
public class Circle implements Shape { private String color; private int x; private int y; private int radius; public Circle(String color) { this.color = color; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setRadius(int radius) { this.radius = radius; } @Override public void draw() { Log.e("---", "Circle: Draw() [Color : " + color + ", x : " + x + ", y :" + y + ", radius :" + radius); } }
-
3. Create a factory to generate objects of an entity class based on the given information.
public class ShapeFactory { private static final HashMap<String, Shape> circleMap = new HashMap<String, Shape>(); public static Shape getShape(String color) { Shape shape = circleMap.get(color); if (shape == null) { shape = new Circle(color); circleMap.put(color, shape); Log.e("getShape", "Creating circle of color : " + color); } return shape; } }
-
4. Use the factory to get objects of entity class by passing color information.
for (int i = 0; i < 20; i++) { Circle circle = (Circle) ShapeFactory.getShape(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); }
14. Agent mode
One class represents the functionality of another class.In proxy mode, we create objects with existing objects to provide functional interfaces to the outside world.It can be understood that an object is created without it in memory and returned directly if it exists.
- Main Solution: Problems caused by direct access to objects, such as: the object to be accessed is on a remote machine.In an object-oriented system, direct access to some objects can cause a lot of trouble to users or the system structure for some reasons, such as the overhead of object creation, the need for security control for some operations, or the need for out-of-process access. We can add an access layer to this object when accessing it.
For example, there are three steps to getting pictures from disk:
-
1. Create an interface.
public interface Image { void display(); }
-
2. Create the entity class RealImage that implements the interface.Corresponding proxy class: ProxyImage.
public class RealImage implements Image { private String fileName; public RealImage(String fileName) { this.fileName = fileName; loadFromDisk(fileName); } private void loadFromDisk(String fileName) { Log.e("RealImage", "loading " + fileName); } @Override public void display() { Log.e("RealImage", "Displaying " + fileName); } }
public class ProxyImage implements Image { private String fileName; private RealImage realImage; public ProxyImage(String fileName) { this.fileName = fileName; } @Override public void display() { if (realImage == null) { realImage = new RealImage(fileName); } realImage.display(); } }
-
3. Use ProxyImage to get objects of RealImage class when requested.
Image image = new ProxyImage("test_10mb.png"); // The first time was new, the image was loaded from disk image.display(); // The second time the cache is fetched, the image does not need to be loaded from disk image.display();
15. Bridge mode
Bridge is used to decouple abstraction from implementation so that they can change independently.This type of design pattern is a structural one, which decouples abstraction from realisation by providing a bridge between them.
- Main Solution: Inheritance can cause class explosion and is not flexible to expand in a variety of possible situations.
Take drawing circles of different colors as an example, the implementation is divided into five steps:
-
1. Create bridges to implement interfaces.
public interface DrawAPI { void drawCircle(int radius, int x, int y); }
-
2. Create an entity bridge implementation class that implements the DrawAPI interface. RedCircle,GreenCircle
public class RedCircle implements DrawAPI { @Override public void drawCircle(int radius, int x, int y) { Log.e("---", "Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", " + y + "]"); } }
-
3. Create abstract classes using DrawAPI interface Shape.
public abstract class Shape { protected DrawAPI drawAPI; protected Shape(DrawAPI drawAPI) { this.drawAPI = drawAPI; } public abstract void draw(); }
-
4. Create an entity class that implements the Shape interface.
public class Circle extends Shape { private int x, y, radius; protected Circle(int x, int y, int radius, DrawAPI drawAPI) { super(drawAPI); this.x = x; this.y = y; this.radius = radius; } @Override public void draw() { drawAPI.drawCircle(radius, x, y); } }
-
5. Draw different colored circles using Shape and DrawAPI classes.
// Draw a red circle Circle circle = new Circle(10, 10, 100, new RedCircle());s circle.draw(); // Draw a green circle Circle circle2 = new Circle(20, 20, 100, new GreenCircle()); circle2.draw();
16. Combination mode
Also known as partial holistic mode, it is used to treat a group of similar objects as a single object.Combination modes combine objects based on a tree structure to represent parts as well as the overall hierarchy.This type of design pattern is structured, creating a tree structure of object groups.
- Main Solution: It blurs the concepts of simple and complex elements in our tree structure. Client programs can handle complex elements like simple elements, thus decoupling the internal structure of complex elements from client programs.
Take the example of creating and printing a hierarchy of employees, the minimum unit example:
-
1. Create an Employee class with a list of Employee objects.
public class Employee { private String name; // department private String dept; // wages private int salary; // Employee list private List<Employee> subordinates; public Employee(String name, String dept, int salary) { this.name = name; this.dept = dept; this.salary = salary; this.subordinates = new ArrayList<Employee>(); } public void add(Employee e) { subordinates.add(e); } public void remove(Employee e) { subordinates.remove(e); } public List<Employee> getSubordinates() { return subordinates; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", dept='" + dept + '\'' + ", salary=" + salary + ", subordinates=" + subordinates + '}'; } }
-
2. Use the Employee class to create and print a hierarchy of employees.
final Employee ceo = new Employee("John", "CEO", 30000); Employee headSales = new Employee("Robert", "Head sales", 20000); Employee headMarketing = new Employee("Michel", "Head Marketing", 20000); Employee clerk1 = new Employee("Laura", "Marketing", 10000); Employee clerk2 = new Employee("Bob", "Marketing", 10000); Employee salesExecutive1 = new Employee("Richard", "Sales", 10000); Employee salesExecutive2 = new Employee("Rob", "Sales", 10000); ceo.add(headSales); ceo.add(headMarketing); headSales.add(salesExecutive1); headSales.add(salesExecutive2); headMarketing.add(clerk1); headMarketing.add(clerk2); Log.e("---", ceo.toString()); // Print /* * Employee{name='John', dept='CEO', salary=30000, * subordinates=[Employee{name='Robert', dept='Head sales', salary=20000, * subordinates=[ * Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]}, * Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]}, * Employee{name='Michel', dept='Head Marketing', salary=20000, * subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]}, * Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]} */
17. Iterator mode
Design patterns that are very common in Java and.Net programming environments.This pattern is used to sequentially access the elements of a collection object without knowing the underlying representation of the collection object.Iterator mode is behavioral.
- The main solution is to traverse the entire integrated object in different ways.
For example, using an iterator to print names is a three-step process:
-
1. Create interfaces:
public interface Iterator { public boolean hasNext(); public Object next(); }
public interface Container { public Iterator getIterator(); }
-
2. Create an entity class that implements the Container interface.This class has an internal class NameIterator that implements the Iterator interface.
public class NameRepository implements Container { private String names[] = {"John", "jingbin", "youlookwhat", "lookthis"}; @Override public Iterator getIterator() { return new NameIterator(); } private class NameIterator implements Iterator { int index; @Override public boolean hasNext() { if (index < names.length) { return true; } return false; } @Override public Object next() { if (hasNext()) { return names[index++]; } return null; } } }
-
3. Use NameRepository to get the iterator and print the name.
NameRepository nameRepository = new NameRepository(); for (Iterator iterator = nameRepository.getIterator(); iterator.hasNext(); ) { String name = (String) iterator.next(); Log.e("---", name); /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */ }
18. Intermediator Model
Used to reduce communication complexity between multiple objects and classes.This pattern provides a mediation class that typically handles communication between different classes, supports loose coupling, and makes code easy to maintain.The intermediary model is behavioral.
- Main Solution: There are a large number of associations between objects, which will inevitably lead to complex system structure. At the same time, if an object changes, we also need to track the objects associated with it and make corresponding processing.
For example, in a public chat room, the minimum unit example steps are:
-
1. Create a mediation class.
public class CharRoom { public static void showMessage(User user, String message) { Log.e("---", new Date().toString() + " [" + user.getName() + "] : " + message); } }
-
2. Create user class.
public class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void sendMessage(String message) { // Using mediation classes CharRoom.showMessage(this, message); } }
-
3. Use the User object to display the communication between them.
User jingbin = new User("jingbin"); jingbin.sendMessage("Hi~ youlookwhat!"); //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat! User jingbin = new User("youlookwhat"); jingbin.sendMessage("Hi~ jingbin!"); //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
19. Memo Mode
Save a state of an object to restore it at the appropriate time.The memo mode is behavioral.
- Main Solution: The so-called memo mode is to capture the internal state of an object without destroying the encapsulation and save the state outside the object so that the object can be restored to its original state in the future.
Using a memo as an example, the minimum unit step is:
-
1. Create a memo Memento class.
public class Memento { private String state; public Memento(String state) { this.state = state; } public String getState() { return state; } public void setState(String state) { this.state = state; } }
-
2. Create Originator class.
public class Originator { private String state; public String getState() { return state; } public void setState(String state) { this.state = state; } public Memento setSateToMemento() { return new Memento(state); } public String getStateFromMemento(Memento memento) { return memento.getState(); } }
-
3. Create CareTaker class.
public class CareTaker { private List<Memento> mementoList = new ArrayList<Memento>(); public void add(Memento memento) { mementoList.add(memento); } public Memento get(int index) { return mementoList.get(index); } }
-
4. Use CareTaker and Originator objects.
// Controller CareTaker careTaker = new CareTaker(); Originator originator = new Originator(); originator.setState("State #1"); originator.setState("State #2"); // Save State careTaker.add(originator.setSateToMemento()); originator.setState("State #3"); // Save State careTaker.add(originator.setSateToMemento()); originator.setState("State #4"); Log.e("---", "Current State: " + originator.getState()); // Saved state String fromMemento1 = originator.getStateFromMemento(careTaker.get(0)); Log.e("---", "First Saved State: " + fromMemento1); String fromMemento2 = originator.getStateFromMemento(careTaker.get(1)); Log.e("---", "Second Saved State: " + fromMemento2); /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */
20. Interpreter mode
Provides a way to evaluate the grammar or expression of a language, which is behavioral.This pattern implements an expression interface that interprets a specific context.This pattern is used in SQL parsing, symbol processing engines, and so on.
- The main solution is to construct an interpreter to interpret sentences for some fixed grammars.
To illustrate a sentence, for example, the minimum unit step is:
-
1. Create an expression interface Expression.
public interface Expression { public boolean interpreter(String content); }
-
2. Create entity classes that implement the above interfaces.TerminalExpression, OrExpression, AndExpression.
public class TerminalExpression implements Expression { private String data; public TerminalExpression(String data) { this.data = data; } @Override public boolean interpreter(String content) { // Is Inclusive Judgment return content.contains(data); } }
public class OrExpression implements Expression { private Expression expression1; private Expression expression2; public OrExpression(Expression expression1, Expression expression2) { this.expression1 = expression1; this.expression2 = expression2; } @Override public boolean interpreter(String content) { return expression1.interpreter(content) || expression2.interpreter(content); } }
public class AndExpression implements Expression { private Expression expression1; private Expression expression2; public AndExpression(Expression expression1, Expression expression2) { this.expression1 = expression1; this.expression2 = expression2; } @Override public boolean interpreter(String content) { return expression1.interpreter(content) && expression2.interpreter(content); } }
-
3. Use the Expression class to create rules and parse them.
/** * Rule: jingbin and youlookwhat are men */ public static Expression getMaleExpression() { TerminalExpression jingbin = new TerminalExpression("jingbin"); TerminalExpression youlookwhat = new TerminalExpression("youlookwhat"); return new OrExpression(jingbin, youlookwhat); } /** * Rule: Julie is a married woman */ public static Expression getMarriedWomanExpression() { TerminalExpression julie = new TerminalExpression("Julie"); TerminalExpression married = new TerminalExpression("Married"); return new AndExpression(julie, married); } Expression maleExpression = getMaleExpression(); // jingbin is male: true Log.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin")); Expression womanExpression = getMarriedWomanExpression(); // Julie is married woman: true Log.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));
21. Responsibility Chain Model
Chain of Responsibility Pattern creates a chain of recipient objects for a request.This pattern gives the type of request and decouples the sender and receiver of the request.This type of design pattern is behavioral.In this mode, each recipient usually contains a reference to another recipient.If an object cannot process the request, it will pass the same request to the next recipient, and so on.
- Main Solution: The handler in the responsibility chain handles the request. The client only needs to send the request to the responsibility chain, and does not need to care about the details of the request processing and the transfer of the request, so the responsibility chain decouples the sender of the request from the handler of the request.
Take the example of printing logs in Android Studio, the minimum unit step:
-
1. Create an abstract recorder class, AbstractLogger.
public abstract class AbstractLogger { public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3; protected int level; // Next element in the chain of responsibility protected AbstractLogger nextLogger; public void setNextLogger(AbstractLogger nextLogger) { this.nextLogger = nextLogger; } public void logMessage(int level, String message) { if (this.level <= level) { write(message); } // Recursive effect, constantly calling the next level of logMessage if (nextLogger != null) { nextLogger.logMessage(level, message); } } protected abstract void write(String message); }
-
2. Create an entity class that extends the recorder class.
public class ConsoleLogger extends AbstractLogger { public ConsoleLogger(int level) { this.level = level; } @Override protected void write(String message) { Log.e("---", "Standard Console::Logger " + message); } }
public class FileLogger extends AbstractLogger { public FileLogger(int level) { this.level = level; } @Override protected void write(String message) { Log.e("---", "File::Logger " + message); } }
public class ErrorLogger extends AbstractLogger { public ErrorLogger(int level) { this.level = level; } @Override protected void write(String message) { Log.e("---", "Error Console::Logger " + message); } }
-
3. Create different types of recorders.Give them different error levels and set the next recorder in each recorder.The next recorder in each recorder represents a part of the chain.
public static AbstractLogger getChainOfLoggers() { ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR); FileLogger fileLogger = new FileLogger(AbstractLogger.DEBUG); ConsoleLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO); errorLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(consoleLogger); return errorLogger; } AbstractLogger logger = getChainOfLoggers(); // ---: Standard Console::Logger this is an information. logger.logMessage(AbstractLogger.INFO, "this is an information."); // ---: File::Logger this is a debug level information. // ---: Standard Console::Logger this is a debug level information. logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information."); // ---: Error Console::Logger this is a error level information. // ---: File::Logger this is a error level information. // ---: Standard Console::Logger this is a error level information. logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");
22. Visitor Mode
In Visitor Mode, we use a Visitor class that changes the execution algorithm for element classes.In this way, the element's execution algorithm can change as the visitor changes.This type of design pattern is behavioral.Depending on the schema, the element object already accepts a visitor object so that the visitor object can handle operations on the element object.
- The main solutions are: stable data structure and variable operation coupling.
In the case of displaying the components of a computer, there are five main steps:
-
1. Define an interface that represents an element.
public interface ComputerPart { public void accept(ComputerPartVisitor computerPartVisitor); }
-
2. Create entity classes that extend the above classes. Keyboard,Monitor,Mouse,Computer
public class Computer implements ComputerPart { private ComputerPart[] parts; public Computer() { this.parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()}; } @Override public void accept(ComputerPartVisitor computerPartVisitor) { for (ComputerPart part : parts) { part.accept(computerPartVisitor); } computerPartVisitor.visit(this); } }
public class Mouse implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } }
-
3. Define an interface that represents the visitor.
public interface ComputerPartVisitor { public void visit(Computer computer); public void visit(Mouse mouse); public void visit(Keyboard keyboard); public void visit(Monitor monitor); }
-
4. Create entity visitors that implement the above classes.
public class ComputerPartDisplayVisitor implements ComputerPartVisitor { @Override public void visit(Computer computer) { Log.e("---", "Displaying Computer."); } @Override public void visit(Mouse mouse) { Log.e("---", "Displaying Mouse."); } @Override public void visit(Keyboard keyboard) { Log.e("---", "Displaying Keyboard."); } @Override public void visit(Monitor monitor) { Log.e("---", "Displaying Monitor."); } }
-
5. Use ComputerPartDisplayVisitor to display the components of Computer.
ComputerPart computer = new Computer(); computer.accept(new ComputerPartDisplayVisitor()); /* *Print: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */
Download
Reference
About me
- QQ: 770413277
- Nuggets: Jinbeen
- GitHub: https://github.com/youlookwhat
- Email: jingbin127@163.com