Design pattern (Design pattern) is a set of classified and cataloged summary of code design experience that is used repeatedly, known to most people.
Design patterns are divided into three types, with a total of 23 types:
Written with reference to articles in Hongyang, Rookie Tutorials, etc. Please correct me if there are any errors. If there is any infringement, please contact me to delete it.
1. Design pattern Observer Pattern (Observer Pattern) Taking WeChat public service as an example
2. Design Pattern Factory Pattern (Factory Pattern) starts with selling Roujiamo
3. Design Pattern Singleton Design Pattern (Singleton Pattern) Complete Analysis
4. Design pattern Strategy pattern (Strategy Pattern) takes role games as the background
5. Design pattern Adapter Pattern (Adapter Pattern) Take mobile phone charger as an example
6. Design Pattern Command Pattern to manage smart home appliances
7. Design Pattern Decorator Pattern takes you back to the legendary world
8. Design mode, appearance mode (Facade Pattern) one-click movie mode
9. Design Pattern Template Method Pattern shows a programmer’s day
10. Design Pattern State Pattern (State Pattern) Take a vending machine as an example
11. Design Pattern Builder Pattern (Builder Pattern) Take building a car and buying a car as an example
12. Design Pattern Prototype Pattern (Prototype Pattern) Take obtaining multiple shapes as an example
13. Design pattern Flyweight Pattern (Flyweight Pattern) takes randomly obtaining multiple shapes as an example
14. Design Pattern Proxy Pattern (Proxy Pattern) Take obtaining pictures from disk as an example
15. Design pattern Bridge Pattern (Bridge Pattern) Take drawing circles of different colors as an example
16. Design pattern combination pattern (Composite Pattern) Take creating and printing employee hierarchy as an example
17. Design pattern Iterator Pattern (Iterator Pattern) Take using an iterator to print names as an example
18. Design Pattern Mediator Pattern (Mediator Pattern) Taking public chat rooms as an example
19. Design Pattern Memento Pattern (Memento Pattern) Take using Memento as an example
20. Design pattern Interpreter Pattern (Interpreter Pattern) Take explaining a sentence as an example
21. Design pattern chain of responsibility pattern (Chain of Responsibility Pattern) Take printing logs in Android Studio as an example
22. Design pattern Visitor Pattern (Visitor Pattern) Take displaying the components of the computer as an example
- Observer
- Factory
- Singleton
- Strategy
- Adapter
- Command
- Decorator
- Facade
- Template Method
- State
- Builder
- Prototype
- Flyweight
- Proxy
- Bridge
- Composite
- Iterator
- Mediator
- Memento
- Chain of Responsibility
- Visitor
Defines one-to-many dependencies between objects, so that when an object changes, all its dependencies will be notified and automatically updated.
There are many places in JDK or Andorid that implement the observer pattern, such as XXXView.addXXXListenter. Of course, XXXView.setOnXXXListener is not necessarily the observer pattern, because the observer pattern is a one-to-many relationship, and for setXXXListener, it is one pair. The relationship between 1 and 1 should be called a callback.
Special interface: Subject.java;
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
Implementation class of 3D service account: 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 );
}
}
/**
* 主题更新信息
*/
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 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
Final test: ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
Let’s briefly list the family of this pattern:
1. Static factory mode
2. Simple factory mode (buying Roujiamo in the store)
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 : // 默认为酸肉夹馍
roujiaMo = new ZSuanRoujiaMo ();
break ;
}
return roujiaMo ;
}
3. Factory method model (opening a branch)
Provides abstract methods for creating Roujia MoStore: RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
Specific implementation of abstract method: XianRoujiaMoStore.java
The branch still uses the simple factory model: XianSimpleRoujiaMoFactory.java
4. Abstract factory pattern (using official raw materials)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
The singleton mode is mainly to avoid the waste of resources caused by creating multiple instances, and multiple instances can easily lead to incorrect results due to multiple calls. Using the singleton mode can ensure that there is only one instance in the entire application .
Definition: Only three steps are needed to ensure the uniqueness of an object
Compare definition:
Hungry Han style [available]: SingletonEHan.java
Contains lazy Han style [double verification lock recommended]: 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 ;
}
Strategy pattern: Defines a family of algorithms and encapsulates them separately to make them interchangeable. This pattern allows algorithm changes to be independent of the customers who use the algorithms.
RoleA roleA = new RoleA ( "---A" );
roleA . setiDisplayBehavior ( new DisplayYZ ())
. setiAttackBehavior ( new AttackXL ())
. setiDefendBehavior ( new DefendTMS ())
. setiRunBehavior ( new RunJCTQ ());
roleA . display (); // 样子
roleA . attack (); // 攻击
roleA . run (); // 逃跑
roleA . defend (); // 防御
Definition: Convert the interface of a class into another interface expected by the client. The adapter allows classes with incompatible interfaces to cooperate with each other. This definition is okay, saying that the function of an adapter is to convert one interface into another interface.
Take the charger as an example: Mobile phone chargers are generally around 5V. Our household AC voltage in China is 220V, so mobile phone charging requires an adapter (voltage reducer).
A mobile phone: Mobile.java
The phone relies on an interface that provides 5V voltage: V5Power.java
What we have is 220V household AC: V220Power.java
Adapter to complete the function of converting 220V to 5V : V5PowerAdapter.java
Final test: Charge the phone:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
Definition: Encapsulate "requests" into objects so that other objects can be parameterized using different requests, queues or logs. Command mode also supports undoable operations. (Simplification: Encapsulate the request into an object and decouple the action requester and action executor.)
QuickCommand quickCloseCommand = new QuickCommand ( new Command []{ new LightOffCommand ( light ), new ComputerOffCommand ( computer ), new DoorCloseCommand ( door )});
controlPanel . setCommands ( 6 , quickOpenCommand );
controlPanel . keyPressed ( 6 );
controlPanel . setCommands ( 0 , new DoorOpenCommand ( door )); // 开门
controlPanel . keyPressed ( 0 );
Decorator Pattern: To extend functionality, decorators provide a more flexible alternative to integration, dynamically attaching responsibilities to objects.
Let’s briefly describe where the decorator pattern comes into play. When we design a class, we need to add some auxiliary functions to this class, and we don’t want to change the code of this class. This is when the decorator pattern comes into play. It's time. This also reflects a principle: classes should be open to extensions and closed to modifications.
Requirements: Design the equipment system of the game. The basic requirement is to be able to calculate the attack power and description of each equipment after being embedded with various gems:
1. Super class of equipment: IEquip.java
2. Implementation classes of each equipment:
3. Super class of decorations (decorations also belong to equipment): IEquipDecorator.java
4. Implementation class of decorations:
5. Final test: Calculate attack power and view description:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
Definition: Provide a unified interface for accessing a group of interfaces in the subsystem. The appearance defines a high-level interface to make the subsystem easier to use. In fact, for the convenience of customers, a group of operations are encapsulated into a method.
Demand: I prefer watching movies, so I bought a projector, computer, stereo, designed the lighting in the room, and bought a popcorn machine. Then when I want to watch a movie, I need one-click viewing and one-click shutdown.
Switch and other operations for each device class:
eg: Popcorn machine: PopcornPopper.java
Cinema class: HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
Final test: one-click movie viewing:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
Definition: Defines the skeleton of an algorithm and defers some steps to subclasses. The template method allows subclasses to redefine the steps of the algorithm without changing the algorithm structure.
Requirements: Briefly describe: Our company has programmers, testers, HR, project managers, etc. The template method mode is used below to record the work status of all personnel.
Three types of roles in the template method pattern
1. Concrete Method
2. Abstract Method
3. Hook Method
Worker superclass: Worker.java
// 具体方法
public final void workOneDay () {
Log . e ( "workOneDay" , "-----------------work start----------------" );
enterCompany ();
work ();
exitCompany ();
Log . e ( "workOneDay" , "-----------------work end----------------" );
}
// 工作 抽象方法
public abstract void work ();
// 钩子方法
public boolean isNeedPrintDate () {
return false ;
}
private void exitCompany () {
if ( isNeedPrintDate ()) {
Log . e ( "exitCompany" , "---" + new Date (). toLocaleString () + "--->" );
}
Log . e ( "exitCompany" , name + "---离开公司" );
}
Programmer implementation class (time can be known): ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
Final test:
See how everyone is working:
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
Check when the programmer left the company:
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
Definition: Allows an object to change its behavior when its internal state changes, making the object appear as if it has modified its class.
The definition is starting to be blurry again. Think about it. When the internal state of an object changes, its behavior changes with the change of state. It looks like a similar one is reinitialized.
Requirements: Take a vending machine as an example (there are statuses such as coin-inserted and un-coin-inserted, and methods of coin-inserting and coin-returning)
Initial implementation of the vending machine to be improved: VendingMachine.java
Improved vending machine (more malleable): VendingMachineBetter.java
// 放钱
public void insertMoney () {
currentState . insertMoney ();
}
// 退钱
public void backMoney () {
currentState . backMoney ();
}
// 转动曲柄
public void turnCrank () {
currentState . turnCrank ();
if ( currentState == soldState || currentState == winnerState ) {
currentState . dispense (); //两种情况会出货
}
}
// 出商品
public void dispense () {
Log . e ( "VendingMachineBetter" , "---发出一件商品" );
if ( count > 0 ) {
count --;
}
}
// 设置对应状态
public void setState ( State state ) {
this . currentState = state ;
}
State interface: State.java
Interface implementation class corresponding to the state:
Improved vending machine test:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
Construction mode is the object creation mode. The construction mode can separate the internal representation of a product from the production process of the product, so that a construction process can generate product objects with different internal representations.
Requirements: Users go to a car store to buy a car.
Analysis: The car shop extracts corresponding cars according to the needs of each user
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 ;
}
}
The store manager picks up the car:
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
Prototype pattern is used to create repeated objects while ensuring performance. This type of design pattern is a creational pattern, which provides an optimal way to create objects.
This pattern implements a prototype interface that is used to create a clone of the current object. This mode is used when the cost of directly creating objects is relatively high. For example, an object needs to be created after an expensive database operation. We can cache the object, return a clone of it on the next request, and update the database when needed to reduce database calls.
Taking obtaining multiple shapes as an example, there are four steps:
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 an entity class that extends the above abstract class. 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 to 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 ();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
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 a clone of the shape stored in the Hashtable.
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
Mainly used to reduce the number of objects created to reduce memory usage and improve performance. This type of design pattern is a structural pattern, which provides a way to reduce the number of objects and thus improve the object structure required by the application.
Flyweight pattern attempts to reuse existing objects of the same type, or create new objects if no matching object is found. We will demonstrate this pattern by creating 5 objects that draw 20 circles in different locations. Since there are only 5 colors available, the color property is used to check the existing Circle object.
Taking randomly obtaining multiple shapes as an example, there are four steps:
1. Create an interface.
public interface Shape {
void draw ();
}
2. Create an entity class that implements the interface.
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 entity classes based on 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 this factory to obtain the object of the 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 ();
}
One class represents the functionality of another class. In proxy pattern, we create objects with existing objects in order to provide a functional interface to the outside world. It can be understood that if there is no such object in the memory, it will be created, and if there is, the object will be returned directly.
Taking obtaining pictures from disk as an example, there are three steps in total:
1. Create an interface.
public interface Image {
void display ();
}
2. Create an 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. When requested, use ProxyImage to obtain an object of the RealImage class.
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
Bridge is used to decouple abstraction and implementation so that the two can change independently. This type of design pattern is a structural pattern, which decouples abstraction and implementation by providing a bridging structure between them.
Taking drawing circles of different colors as an example, the implementation is divided into five steps:
1. Create a bridge implementation interface.
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. Use the DrawAPI interface to create the abstract class 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. Use the Shape and DrawAPI classes to draw circles of different colors.
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
Also called part-whole pattern, it is used to treat a group of similar objects as a single object. The composition mode combines objects according to a tree structure, which is used to represent part and whole hierarchies. This type of design pattern is a structural pattern, which creates a tree structure of groups of objects.
Take creating and printing an employee hierarchy as an example, the smallest unit example:
1. Create an Employee class with a list of Employee objects.
public class Employee {
private String name ;
// 部门
private String dept ;
// 工资
private int salary ;
// 员工 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 the employee hierarchy.
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 ());
// 打印
/*
* 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=[]}]}]}
*/
Very common design pattern in Java and .Net programming environments. This pattern is used to access the elements of a collection object sequentially without knowing the underlying representation of the collection object. The iterator pattern is a behavioral pattern.
Taking using an iterator to print names as an example, there are three steps in total:
1. Create an interface:
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 inner 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
*/
}
Used to reduce the complexity of communication between multiple objects and classes. This pattern provides an intermediary class that typically handles communication between different classes and supports loose coupling, making the code easier to maintain. The mediator model is a behavioral model.
Taking a public chat room as an example, the minimum unit example steps are:
1. Create an intermediary class.
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2. Create the 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 ) {
// 使用中介类
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!
Save a certain state of an object so that it can be restored at an appropriate time. The memo mode is a behavioral mode.
Taking using memo as an example, the minimum unit steps are:
1. Create the 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 the 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 the 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.
// 管理者
CareTaker careTaker = new CareTaker ();
Originator originator = new Originator ();
originator . setState ( "State #1" );
originator . setState ( "State #2" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #3" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #4" );
Log . e ( "---" , "Current State: " + originator . getState ());
// 得到保存的状态
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
*/
Provides a way to evaluate the grammar or expressions of a language and is a behavioral pattern. This pattern implements an expression interface that interprets a specific context. This mode is used in SQL parsing, symbol processing engines, etc.
Take explaining a sentence as an example, the minimum unit steps:
1. Create an expression interface Expression.
public interface Expression {
public boolean interpreter ( String content );
}
2. Create an entity class that implements the above interface. TerminalExpression, OrExpression, AndExpression.
public class TerminalExpression implements Expression {
private String data ;
public TerminalExpression ( String data ) {
this . data = data ;
}
@ Override
public boolean interpreter ( String content ) {
// 是包含判断
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.
/**
* 规则:jingbin 和 youlookwhat 是男性
*/
public static Expression getMaleExpression () {
TerminalExpression jingbin = new TerminalExpression ( "jingbin" );
TerminalExpression youlookwhat = new TerminalExpression ( "youlookwhat" );
return new OrExpression ( jingbin , youlookwhat );
}
/**
* 规则:Julie 是一个已婚的女性
*/
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" ));
The Chain of Responsibility Pattern creates a chain of recipient objects for a request. This pattern decouples the sender and receiver of the request based on the type of request. This type of design pattern is a behavioral pattern. In this pattern, typically each receiver contains a reference to another receiver. If an object cannot handle the request, it passes the same request to the next recipient, and so on.
Taking printing logs in Android Studio as an example, the minimum unit steps are:
1. Create an abstract logger class AbstractLogger.
public abstract class AbstractLogger {
public static int INFO = 1 ;
public static int DEBUG = 2 ;
public static int ERROR = 3 ;
protected int level ;
// 责任链中的下一个元素
protected AbstractLogger nextLogger ;
public void setNextLogger ( AbstractLogger nextLogger ) {
this . nextLogger = nextLogger ;
}
public void logMessage ( int level , String message ) {
if ( this . level <= level ) {
write ( message );
}
// 递归效果,不断调用下一级 logMessage
if ( nextLogger != null ) {
nextLogger . logMessage ( level , message );
}
}
protected abstract void write ( String message );
}
2. Create an entity class that extends the logger 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 loggers. Give them different error levels and within each logger set the next logger. The next logger in each logger represents 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." );
In the visitor pattern, we use a visitor class, which changes the execution algorithm of the element class. In this way, the element's execution algorithm can change as the visitor changes. This type of design pattern is a behavioral pattern. According to the schema, the element object has accepted a visitor object so that the visitor object can handle operations on the element object.
Taking the components of a display computer as an example, it is mainly implemented in five steps:
1. Define an interface that represents the element.
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2. Create an entity class that extends the above class. 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 visitors.
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 ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/