设计模式之行为型模式

模板模式

定义:定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。即完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。

模板模式的特点:抽象父类、具体类

适用场景:流程一般固定,但是具体实现有区别

参考博客: 模版模式的应用实际举例模板模式应用场景实例张彦峰ZYF的博客-CSDN博客

demo

抽象父类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* TODO protected void someEat() 为什么会报错?
*
* @author huihui
* @date 2023/9/11 21:51
*/
public abstract class AbstractEat {

protected void someEat(){
this.eat();
this.afterEat();
this.eatAgain();
}

public abstract void eat();
public abstract void afterEat();

public abstract void eatAgain();

}

具体子类1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* TODO
*
* @author huihui
* @date 2023/9/11 21:56
*/
public class SomeFirst extends AbstractEat {
@Override
public void eat() {
System.out.println("用手吃饭");
}

@Override
public void afterEat() {
System.out.println("用手擦嘴");
}

@Override
public void eatAgain() {
System.out.println("用手再吃");
}
}

具体子类2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* TODO
*
* @author huihui
* @date 2023/9/11 21:57
*/
public class SomeOneSecond extends AbstractEat {
@Override
public void eat() {
System.out.println("用脚吃饭");
}

@Override
public void afterEat() {
System.out.println("用脚擦嘴");
}

@Override
public void eatAgain() {
System.out.println("用脚再吃");
}
}

策略模式

定义:完成一件事,目的唯一但方法不唯一

适用场景:去买东西计算你最后应支付的金额就是一个任务,计算实付金额有三种方式:打折扣、满多少减多少、直接免单不用付钱。再比如,你要去旅行,你可以选择飞机、高铁、自驾游到目的地。也可以使用策略模式。你要到达旅游的目的地是一个任务,有三种方式都可以到达,不同的交通方式时间不同,实现代码如下。

demo

一个接口(需要实现的目的)

1
2
3
public interface Learning {
void learn(String ways);
}

多个接口的实现类(不同的方法论)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LearnByPeople implements Learning{
@Override
public void learn(String ways) {
System.out.println("通过people学习"+ways);
}
}
------------
public class LearnByTV implements Learning{
@Override
public void learn(String ways) {
System.out.println("通过TV学习"+ways);
}
}

上下文(将不同的实现行为通过参数传入策略模式Context的构造方法,可以在使用这些行为的类中消除条件语句。)

1
2
3
4
5
6
7
8
9
public class Context {
private Learning learning;
public void setLearning(Learning learning){
this.learning = learning;
};
public void learned(String ways){
learning.learn(ways);
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 public static void main( String[] args )
{
Context context = new Context();
context.setLearning(new LearnByPeople());
context.learned("通过人学的效率不错");

context.setLearning(new LearnByTV());
context.learned("通过电视学习的效果也还行");

}


-------
通过people学习通过人学的效率不错
通过TV学习通过电视学习的效果也还行

备忘录模式(快照模式)

定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

适用场景:需要提供可以恢复状态的机制的时候可以用。当用户需要时能够比较方便地将数据恢复到某个历史的状态。(对于封装的内部信息,除了创建它的发起人(不是被封装的那个类),其他都不能访问,满足单一职责)

demo

备忘录接口

1
2
public interface MementoIF {
}

备忘录实现类

1
2
3
4
5
6
7
8
9
10
11
public class Memento implements MementoIF{
private String state;

public Memento(String state) {
this.state = state;
}

public String getState(){
return state;
}
}

备忘录发起者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Originator {
private String state;

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}
public Memento saveToMemento() {
return new Memento(state);
}

public String getStateFromMemento(MementoIF memento) {
return ((Memento) memento).getState();
}

}

备忘录管理者

1
2
3
4
5
6
7
8
9
10
11
12
public class CareTaker {
private List<MementoIF> mementoList = new ArrayList<MementoIF>();

public void add(MementoIF memento) {
mementoList.add(memento);
}

public MementoIF get(int index) {
return mementoList.get(index);
}

}

被记录的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class SunHuiEntity {
private String name;
private Integer age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class App 
{
public static void main( String[] args )
{
SunHuiEntity sh = new SunHuiEntity();
sh.setAge(12);
sh.setName("huihuihui");
//创建者
Originator memo = new Originator();
memo.setState(sh.getName());
//改名
sh.setName("huihui");
//管理者
CareTaker careTaker = new CareTaker();
careTaker.add(memo.saveToMemento());
//只有创建者能够读取备忘录
String oldName = memo.getStateFromMemento(careTaker.get(0));
System.out.println( "oldName:"+oldName+"\nnewName:"+sh.getName() );
}
}

责任链模式

定义:一个请求可能被多个接收者中的一个或若干个处理但不清楚具体是要哪一个接收者来处理,责任链模式会使请求的发送者和接受者解耦,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递。

适用场景: 一个 请求的处理 , 需要多个对象中的一个或若干个对象协作进行处理

实现方式:多个处理类继承同一个接口,并且多个处理类需要有一个指定下一个处理者的方法

组成:

demo

统一接受请求抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class Approver {
String name;
Approver successor;

public Approver(String name) {
this.name = name;
}

public abstract void processRequest(PurchaseRequest request);

public void SetSuccessor(Approver approver){
this.successor = approver;
}
}

请求内容实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class PurchaseRequest {
private int Type = 0;
private int Number = 0;
private float Price = 0;
private int ID = 0;
public PurchaseRequest(int Type, int Number, float Price) {
this.Type = Type;
this.Number = Number;
this.Price = Price;
}

public int GetType() {
return Type;
}

public float GetSum() {
return Number * Price;
}

public int GetID() {
return (int) (Math.random() * 1000);
}

}

发送请求客户端

1
2
3
4
5
6
7
8
public class Client {
public Client() {

}
public PurchaseRequest sendRequest(int Type, int Number, float Price) {
return new PurchaseRequest(Type, Number, Price);
}
}

多个具体实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//具体实现类1
public class GroupApprover extends Approver{

public GroupApprover(String Name) {
super(Name + "-GroupLeader");
}

@Override
public void processRequest(PurchaseRequest request) {
if (request.GetSum() < 5000) {
System.out.println("**This request " + request.GetID() + " will be handled by " + this.name + " **");
} else {
successor.processRequest(request);
}

}
}

//具体实现类2
public class DepartmentApprover extends Approver{

public DepartmentApprover(String Name) {
super(Name + "-GroupLeader");
}

@Override
public void processRequest(PurchaseRequest request) {
if ((5000 <= request.GetSum()) && (request.GetSum() < 10000)) {
System.out.println("**This request " + request.GetID()
+ " will be handled by " + this.name + " **");
} else {
successor.processRequest(request);
}

}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class App 
{
public static void main( String[] args )
{
Client mClient = new Client();
Approver GroupLeader = new GroupApprover("Tom");
Approver DepartmentLeader = new DepartmentApprover("Jerry");
//定义责任链
GroupLeader.SetSuccessor(DepartmentLeader);
DepartmentLeader.SetSuccessor(null);
GroupLeader.processRequest(mClient.sendRequest(1, 89, 1000));
System.out.println( "Hello World!" );
}
}

提问:责任链模式和策略模式的区别是什么?

观察者模式

定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

适用场景:类似QQ上下线、公众号推送此类的消息通知

实现方式:通过抽象观察者和被观察者实现一定程度的解耦

组成:抽象观察者、抽象被观察者、具体观察者、具体被观察者

demo

抽象被观察者

1
2
3
4
5
6
7
8
public abstract class Subject {

public abstract void addObserver(Observer observer);

public abstract void delObserver(Observer observer);

public abstract void notifyObserver();
}

具体被观察者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class WeChatServer extends Subject{
private List<Observer> observers;
private String message;

public WeChatServer() {
this.observers = new ArrayList<Observer>();
}

@Override
public void addObserver(Observer observer) {
observers.add(observer);
}

@Override
public void delObserver(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObserver() {
for (Observer o : observers) {
o.update(message);
}

}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服务更新消息: " + s);
// 消息更新,通知所有观察者
notifyObserver();
}

}

抽象观察者

1
2
3
public abstract class Observer {
public abstract void update(String massage);
}

具体观察者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class User extends Observer{
private String name;
private String message;

public User(String name) {
this.name = name;
}

@Override
public void update(String message) {
this.message = message;
read();
}

public void read() {
System.out.println(name + " 收到推送消息: " + message);
}

}