11种创造型设计模式(下)

2024-03-21 02:28
文章标签 设计模式 创造型

本文主要是介绍11种创造型设计模式(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

观察者模式

我们可以比喻观察者模式是一种类似广播的设计模式

介绍

观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象是Subject,依赖的对象是Observer,Subject通知Observer变化。

image-20240314134453836

代码

说明:

WeatherStation 充当主题,WeatherDisplay 充当观察者。WeatherStation 维护了一个观察者列表,提供了注册、移除和通知观察者的方法。当天气更新时,调用 updateWeather() 方法来模拟更新天气并通知观察者。观察者收到通知后会调用 update() 方法来更新天气信息。

image-20240314135021001

import java.util.ArrayList;
import java.util.List;
​
// 主题接口
interface WeatherSubject {void registerObserver(WeatherObserver observer);void removeObserver(WeatherObserver observer);void notifyObservers();
}
​
// 观察者接口
interface WeatherObserver {void update(String weather);
}
​
// 具体主题类
class WeatherStation implements WeatherSubject {private List<WeatherObserver> observers = new ArrayList<>();private String weather;
​@Overridepublic void registerObserver(WeatherObserver observer) {observers.add(observer);}
​@Overridepublic void removeObserver(WeatherObserver observer) {observers.remove(observer);}
​@Overridepublic void notifyObservers() {for (WeatherObserver observer : observers) {observer.update(weather);}}
​// 模拟天气更新,并通知观察者public void updateWeather(String newWeather) {this.weather = newWeather;notifyObservers();}
}
​
// 具体观察者类
class WeatherDisplay implements WeatherObserver {private String observerName;
​public WeatherDisplay(String observerName) {this.observerName = observerName;}
​@Overridepublic void update(String weather) {System.out.println(observerName + " 收到天气更新: " + weather);}
}
​
public class WeatherObserverExample {public static void main(String[] args) {// 创建天气主题WeatherStation weatherStation = new WeatherStation();
​// 创建天气显示观察者WeatherObserver observer1 = new WeatherDisplay("观察者1");WeatherObserver observer2 = new WeatherDisplay("观察者2");
​// 注册观察者weatherStation.registerObserver(observer1);weatherStation.registerObserver(observer2);
​// 模拟天气更新weatherStation.updateWeather("晴天");
​// 移除观察者2weatherStation.removeObserver(observer2);
​// 再次模拟天气更新weatherStation.updateWeather("下雨");}
}

观察者莫斯在JDK中的使用分析

JDK中的Observable使用了观察者模式。

直接追源码,看它的结构:

1、addObserver添加
2、deleteObserver:删除
3、notifyObserver:通知
4、Vector<Observer>观察者列表

image-20240314135417488

image-20240314135547827

总结

个人理解:观察者模式就是一种似广播的模式,一个站对多个对象。

观察者模式(Observer Pattern)是一种软件设计模式,它定义了一种一对多的依赖关系,使得多个观察者对象同时监听某一个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。

结构

观察者模式通常包含以下角色:

  1. Subject(主题):它是被观察的对象,当其状态发生变化时会通知观察者。主题可以是一个接口或抽象类,定义了注册、删除和通知观察者的方法。

  2. ConcreteSubject(具体主题):实现了主题接口或抽象类,它存储了一系列观察者对象,状态发生变化时会通知这些观察者。

  3. Observer(观察者):定义了一个更新接口,以便主题在状态发生变化时能够通知到它。

  4. ConcreteObserver(具体观察者):实现了观察者接口,它需要注册到具体主题对象中,以便在主题状态发生变化时接收通知并进行相应的处理。

工作原理

  1. 当主题对象的状态发生变化时,会调用主题对象的通知方法。

  2. 主题对象的通知方法会遍历注册在其中的所有观察者对象,并调用它们的更新方法。

  3. 观察者对象在接收到通知后会执行相应的更新操作,以使自身状态与主题对象保持同步。

优点

  • 松耦合:观察者模式将主题对象和观察者对象之间的耦合度降到了最低,主题和观察者之间彼此独立地变化。

  • 扩展性好:可以根据需要随时增加新的观察者或主题,使系统更易于扩展。

  • 符合开闭原则:系统中新增加观察者或主题不需要修改原有的代码。

适用场景

  • 当一个对象的改变需要同时影响其他对象,而且不知道具体有多少对象需要被通知时,可以考虑使用观察者模式。

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,但又需要独立于其变化时,可以考虑使用观察者模式。

  • 当一个对象的改变需要同时影响到其他对象,而且你不希望知道具体有多少对象需要被通知时,可以考虑使用观察者模式。

观察者模式在软件开发中被广泛应用,例如 GUI 开发中的事件监听器、Android 中的广播机制等。

中介者模式

可以将中介者模式理解成一种通过中间类来进行通信和协调的设计模式

介绍

1、中介者模式是一种行为型设计模式,用来减少对象间的直接耦合
2、在中介者模式中,对象之间不再相互通信,而是通过一个中介者对象来进行通信。这有助于降低系统的复杂度,提高系统的可维护性和可扩展性

中介者模式中的角色:

1、中介者(Mediator):负责协调对象之间的交互关系,通过中介者对象来通知其他对象
2、同事(Colleague):维护一个对中介者对象的引用,通过中介者对象进行通信

代码

image-20240316174202282

import java.util.ArrayList;
import java.util.List;
​
// 中介者接口
interface Mediator {void sendMessage(String message, Colleague colleague);
}
​
// 具体中介者
class ConcreteMediator implements Mediator {private List<Colleague> colleagues;
​public ConcreteMediator() {colleagues = new ArrayList<>();}
​public void addColleague(Colleague colleague) {colleagues.add(colleague);}
​@Overridepublic void sendMessage(String message, Colleague colleague) {for (Colleague col : colleagues) {// 排除发送者自身if (col != colleague) {col.receiveMessage(message);}}}
}
​
// 同事接口
interface Colleague {void sendMessage(String message);
​void receiveMessage(String message);
}
​
// 具体同事类
class ConcreteColleague implements Colleague {private Mediator mediator;
​public ConcreteColleague(Mediator mediator) {this.mediator = mediator;}
​@Overridepublic void sendMessage(String message) {mediator.sendMessage(message, this);}
​@Overridepublic void receiveMessage(String message) {System.out.println("Received message: " + message);}
}
​
public class Main {public static void main(String[] args) {ConcreteMediator mediator = new ConcreteMediator();
​ConcreteColleague colleague1 = new ConcreteColleague(mediator);ConcreteColleague colleague2 = new ConcreteColleague(mediator);
​mediator.addColleague(colleague1);mediator.addColleague(colleague2);
​colleague1.sendMessage("Hello, colleague2!");colleague2.sendMessage("Hi, colleague1!");}
}
 

中介者模式和观察者模式对比

学完这两种设计模式,我们会发现两种设计模式,其实是有很多相似的地方的。

1、中介者模式发消息其实是针对的发的,类似QQ聊天中的单聊。

2、观察者模式发消息是广播式的发,类似QQ聊天中的群聊

这里又可以放入消息队列中:

  1. 观察者模式类似于fanout交换机:在观察者模式中,一个被观察者对象(通常称为主题或者被观察者)可以同时通知多个观察者对象,就像fanout交换机一样,它会将消息广播给所有与之绑定的队列。每个观察者对象都会收到相同的消息,并且它们之间的关系是松散耦合的。

  2. 中介者模式类似于direct交换机:在中介者模式中,对象之间的通信通过一个中介者进行,中介者根据消息的内容将消息传递给特定的对象,就像direct交换机一样,它会根据消息的路由键将消息发送到与之匹配的队列。这种方式下,对象之间的关系是通过中介者来进行管理和协调的。

总结

要点总结:

  1. 中介者模式通过引入中介者对象来减少对象之间的直接耦合。

  2. 中介者模式可以降低系统的复杂性,提高系统的可维护性和可扩展性。

  3. 中介者模式的核心在于中介者对象,它负责协调和管理对象之间的交互关系。

  4. 同事对象通过中介者对象来进行通信,不再直接相互依赖。

使用场景:

中介者模式适用于多个对象之间存在复杂的交互关系,但是又不希望它们之间相互耦合的场景,例如,图形用户界面中的控件之间的交互、多人协作系统中的用户之间的通信等。

备忘录模式

可以将备忘录模式理解为一种通过存储对象状态并能够改变状态的设计模式

介绍

1. 备忘录模式在不破坏封装性的前提下,捕获一个对象内部状态,并在对象之外报错这个状态。这样就可以将该对象恢复到原先保存状态
2. 备忘录对象主要用来记录一个对象的某种状态/某些数据,当要回退时,可以从备忘录对象获取原来的数据进行恢复操作
3. 属于行为型模式

 角色

1. 发起人(Originator):负责创建备忘录对象,将其状态保存到备忘录中,并从备忘录中恢复状态。
2. 备忘录(Memento):用于存储发起人对象的内部状态,通常提供对状态的访问方法。
3. 管理者(Caretaker):负责保存备忘录对象,但不会对备忘录的内容进行操作或者检查。

 使用流程

1. 发起人创建备忘录对象,并将其内部状态保存到备忘录中。
2. 管理者保存备忘录对象。
3. 在需要时,发起人从备忘录中恢复状态。

 代码

结合备忘录模式和代理模式,实现一个简单的文档编辑器。编辑器包含一个文本输入框,用户可以在文本输入框中输入内容。我们将使用代理模式来控制对文本输入框的访问,并使用备忘录模式来保存文本输入框的历史状态,以便用户可以撤销操作。


import java.util.Stack;// 备忘录类
class TextMemento {private String text;public TextMemento(String text) {this.text = text;}public String getText() {return text;}
}// 发起人类
class TextEditor {private String text;private Stack<TextMemento> history;public TextEditor() {this.text = "";this.history = new Stack<>();}public void setText(String text) {this.text = text;}public String getText() {return text;}public void save() {history.push(new TextMemento(text));}public void undo() {if (!history.isEmpty()) {text = history.pop().getText();}}
}// 代理类
class TextEditorProxy {private TextEditor editor;public TextEditorProxy() {this.editor = new TextEditor();}public void setText(String text) {editor.setText(text);}public String getText() {return editor.getText();}public void save() {editor.save();}public void undo() {editor.undo();}
}public class Main {public static void main(String[] args) {TextEditorProxy editor = new TextEditorProxy();// 用户输入文本editor.setText("Hello, World!");// 用户保存当前文本状态editor.save();// 用户继续输入文本editor.setText("This is a text editor.");// 用户再次保存当前文本状态editor.save();// 用户进行撤销操作editor.undo();System.out.println("Current text: " + editor.getText());}
}

 小结

个人理解:备忘录模式就是一种用来保存某类对象某个状态的模式。


备忘录模式的主要目的是允许在不暴露对象内部结构的情况下,捕获和恢复对象的状态。这种模式常用于需要在某个时间点保存对象状态,并在需要时将其恢复的情况下。
 

1. 优点

  •    - 备忘录模式使得发起人对象的状态保存与恢复得以分离,提高了系统的封装性和灵活性。
  •    - 可以通过备忘录模式实现撤销操作,使得用户可以在操作错误时进行恢复。

2. 缺点
   - 如果备忘录对象过多或者状态信息过大,可能会导致内存消耗较大。
   - 备忘录模式可能会增加系统的复杂性,特别是在需要管理多个备忘录对象时。

3. 为了节约内存,备忘录模式可以和原型模式配合使用

解释器模式(Interpreter模式)

可以理解解释器模式是一种定义一种语言文法的表示,并提供一个解释器来解释这种语言的语句的设计模式

介绍

  1. 是一种行为型设计模式。用于定义一个语言的文法,并提供解释器来解释该语言中的句子

  2. 目的:用于解释一种特定语言的语法规则,并提供方法来解释和执行该语言中的矩阵。

  3. 使用例子:编译器、运算表达式计算、正则表达式、机器人等

角色

  1. 抽象表达式(Abstract Expression):定义一个解释器的接口,其中包括一个解释方法,用于解释语言中的句子。 (抽象表达式,声明一个抽象的解释操作,为抽象语法树中所有节点所共享)

  2. 终结符表达式(Terminal Expression):实现抽象表达式接口的类,用于解释语言中的终结符或基本元素。 (实现文法中的终结符相关的解释操作)

  3. 非终结符表达式(Non-terminal Expression):实现抽象表达式接口的类,用于解释语言中的非终结符或复合元素。 (为文法中的非终结符实现解释操作)

  4. 上下文(Context):包含了需要解释的语句或表达式的信息,提供给解释器进行解释。 (环境角色,含有解释器之外的全局信息)

使用流程

  • 客户端创建一个上下文对象,并在上下文中设置需要解释的语句或表达式。

  • 客户端创建解释器对象,并将上下文对象传递给解释器。

  • 解释器根据语言的文法规则逐步解释并执行语句或表达式,生成最终的结果。

输入Context he TerminalExpression 信息通过Client输入即可。

代码

image-20240317152640259

package com.pxl.test.Designpattern;
​
import java.util.Stack;
​
// 抽象表达式接口
interface Expression {int interpret();
}
​
// 终结符表达式:数字
class Number implements Expression {private int value;
​public Number(int value) {this.value = value;}
​@Overridepublic int interpret() {return value;}
}
​
// 非终结符表达式:算术运算符表达式
class ArithmeticOperator implements Expression {private Expression leftOperand;private Expression rightOperand;private char operator;
​public ArithmeticOperator(Expression leftOperand, Expression rightOperand, char operator) {this.leftOperand = leftOperand;this.rightOperand = rightOperand;this.operator = operator;}
​@Overridepublic int interpret() {if (operator == '+') {return leftOperand.interpret() + rightOperand.interpret();} else if (operator == '-') {return leftOperand.interpret() - rightOperand.interpret();}// Handle other operators if neededreturn 0;}
}
​
// 上下文类
class Context {public Stack<Expression> stack = new Stack<>();
​public void pushExpression(Expression expression) {stack.push(expression);}
​public Expression popExpression() {return stack.pop();}
​public boolean isOperator(Expression expression) {return expression instanceof ArithmeticOperator;}
}
​
// 解释器
class Parser {private Context context;
​public Parser(Context context) {this.context = context;}
​public int parse(String input) {String[] tokens = input.split("\\s+");for (String token : tokens) {if ("+".equals(token)) {Expression rightOperand = context.popExpression();Expression leftOperand = context.popExpression();context.pushExpression(new ArithmeticOperator(leftOperand, rightOperand, '+'));} else if ("-".equals(token)) {Expression rightOperand = context.popExpression();Expression leftOperand = context.popExpression();context.pushExpression(new ArithmeticOperator(leftOperand, rightOperand, '-'));} else {context.pushExpression(new Number(Integer.parseInt(token)));}}
​return context.popExpression().interpret();}
}
​
public class ExpressionMain {public static void main(String[] args) {String input = "3 4 - 5 +";Context context = new Context();Parser parser = new Parser(context);int result = parser.parse(input);System.out.println("Result: " + result); // 输出}
}

在SpelExpressionParser类中的使用

image-20240317153515523

image-20240317153542880

image-20240317153719066

public class Test {public static void main(String[] args) {SpelExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression("10 *(2+1)");int value = (int) expression.getValue();System.out.println(value);}
}

小结

个人理解:解释器模式通过定义一些基本元素和操作(终结符表达式)和一些复杂规则(非终结符表达式),让解释器进行解释,获得想要的结果

解释器模式确实通过定义基本元素和操作(终结符表达式)以及复杂规则(非终结符表达式)来构建解释器,从而实现对给定语言或语法的解释和执行。终结符表达式代表了文法中的最基本的元素或操作,而非终结符表达式则表示了文法中的复杂规则或组合规则。通过将这些表达式组合起来,解释器能够解释和执行整个语言表达式,从而得到最终的结果。

  1. 优点

    • 简化了语言的解释和执行过程,使得添加新的语法规则或扩展现有规则变得容易。

    • 易于实现和理解,对于特定领域的语言解释非常高效。

  2. 缺点

    • 难以维护复杂的文法规则,特别是文法变化频繁或文法非常复杂时。

    • 可能会导致类的数量急剧增加,增加了系统的复杂性。

状态模式

可以理解状态模式是一种不断改变状态改变类本质的设计模式,如一个人一样,小时候和长大后是不同的状态了,但是还是同一个人。

介绍

1、状态模式主要来解决对象在多种状态转换时,需要对外输出不同行为的问题。状态和行为是一一对应的,状态之间可以互相转换

2、当一个对象的内在状态改变时,允许改变其行为,这个对象看起来(可以举例称一个人,小时候和长大后状态不同了,但是还是同一个人)

原理类图:

image-20240318154315850

说明:

1、Context类为环境角色,用于维护State实例,这个实例定义当前状态
2、State是抽象状态角色,定义一个接口封装与Context的一个特点接口相关行为
3、ConcreteState具体的状态角色,每个子类实现一个与Context的一个状态相关行为

代码

image-20240318155537417

状态模式用于管理抽奖的不同状态,包括初始状态、中奖状态和未中奖状态。每个状态都实现了LotteryState接口,并实现了对应的抽奖逻辑。LotteryContext类用于维护当前的状态,并委托给当前状态处理抽奖操作。在测试类中,进行了5次抽奖操作,每次抽奖都会根据当前状态执行相应的逻辑。

下面代码中,不断的在setState(),将它的类在进行转变,从初始化状态类,转变成未中奖/中奖类

package com.pxl.test.Designpattern;
​
// 定义抽奖状态接口
interface LotteryState {void draw(LotteryContext context);
}
​
// 初始状态
class InitialState implements LotteryState {@Overridepublic void draw(LotteryContext context) {// 在初始状态下,可以进行抽奖System.out.println("正在抽奖,请稍候...(第一次初始化状态。。。)");// 模拟抽奖逻辑int luckyNumber = (int) (Math.random() * 100);if (luckyNumber < 50) {System.out.println("恭喜你中奖了!");context.setState(new WinnerState()); // 切换到中奖状态} else {System.out.println("很遗憾,你没有中奖。");context.setState(new NotWinnerState()); // 切换到未中奖状态}}
}
​
// 中奖状态
class WinnerState implements LotteryState {@Overridepublic void draw(LotteryContext context) {// 已经中奖了,不能再抽奖System.out.println("你已经中过奖了,请等待下一次抽奖。");}
}
​
// 未中奖状态
class NotWinnerState implements LotteryState {@Overridepublic void draw(LotteryContext context) {// 在未中奖状态下,可以进行抽奖System.out.println("正在抽奖,请稍候...");// 模拟抽奖逻辑int luckyNumber = (int) (Math.random() * 100);if (luckyNumber < 50) {System.out.println("恭喜你中奖了!");context.setState(new WinnerState()); // 切换到中奖状态} else {System.out.println("很遗憾,你没有中奖。");}}
}
​
// 抽奖上下文
class LotteryContext {private LotteryState state;
​public LotteryContext() {this.state = new InitialState(); // 初始状态为初始状态}
​public void setState(LotteryState state) {this.state = state;}
​public void draw() {state.draw(this); // 委托状态处理抽奖操作}
}
​
// 测试类
public class StateMain {public static void main(String[] args) {LotteryContext context = new LotteryContext();
​// 进行5次抽奖for (int i = 0; i < 5; i++) {context.draw();System.out.println("---------------------------------");}}
}

小结

个人理解:

状态模式是一种不断改变自己状态(就是不断通过接口实现类进行转变),实现系统灵活性的模式。

优化点:将枚举类代替状态类,避免类爆炸。(但是要注意的是这种会违反开闭原则)

状态模式通过定义不同的状态类以及相应的状态转换规则,使得对象能够根据内部状态的改变而改变自身的行为。这种动态的状态转换使得系统具有了更大的灵活性和可扩展性。通过接口实现类之间的转变,状态模式使得系统可以在运行时根据需求动态地改变对象的状态,而不需要修改对象的代码。这种灵活性使得状态模式在需要对象根据不同条件改变行为的场景中非常有用。

状态模式是一种强大的设计模式,但它也有其优点和缺点。

优点:

  1. 清晰的状态转换:状态模式将每个状态封装到一个类中,使得状态之间的转换变得清晰明确,易于理解和维护。

  2. 简化条件判断:通过将状态的行为抽象为独立的类,状态模式消除了长串的条件判断语句,使得代码更加简洁清晰。

  3. 符合开闭原则:状态模式通过封装每个状态和状态之间的转换规则,使得新增状态或者修改现有状态的行为变得容易,符合开闭原则。

  4. 提高可扩展性:状态模式使得系统在不同状态下可以拥有不同的行为,新增状态只需要添加新的状态类而不需要修改现有代码,提高了系统的可扩展性。

  5. 促进了模块化设计:每个状态都被封装成一个独立的类,使得系统更加模块化,每个模块负责一个特定的状态,易于理解和维护

缺点:

  1. 可能导致类爆炸:当系统中存在大量的状态时,可能会导致类的数量急剧增加,使得系统变得复杂。因此,在设计状态模式时需要合理把握状态的数量。

  2. 增加了系统复杂性:状态模式引入了多个状态类和状态之间的转换规则,可能会增加系统的复杂性,使得理解和维护变得困难。

  3. 不适用于简单状态转换:如果系统中仅有少量的状态且状态之间的转换比较简单,使用状态模式可能会显得过于繁琐,不适合于简单的状态转换场景。

  4. 可能导致对象间的依赖增加:当状态对象需要访问其他对象的状态或者信息时,可能会导致状态对象之间的依赖增加,使得系统变得复杂。

使用场景

  1. 对象行为随状态变化而变化

  2. 条件语句导致代码复杂(避免大量条件判断)

  3. 各个状态类之间相互独立

  4. 例如说在借阅平台中,状态从审核 -> 借阅 ->归还

策略模式

策略模式是一种通过改变策略,改变执行方式的设计模式

介绍

1、策略模式(Strategy Pattern)是一种行为设计模式,它允许在运行时选择算法的行为。它将算法封装成独立的类,使得它们可以相互替换,而不会影响客户端使用算法的方式。

2、把变化的代码从不变的代码中分离开;针对接口编程而不是具体类(定义了策略接口);多用组合/聚合,少用继承(客户通过组合方法实现策略)

代码

image-20240318163254403

DiscountStrategy 是策略接口,定义了抽象的折扣计算方法。然后,我们有三个具体的策略类实现了这个接口,分别是NoDiscountStrategyFixedDiscountStrategyThresholdDiscountStrategy,分别代表无折扣、固定折扣和满减折扣。ShoppingCart 类作为上下文类,接受一个折扣策略作为参数,然后根据具体的策略计算最终的价格。通过这种方式,客户端可以轻松地切换不同的折扣策略,而不需要修改ShoppingCart类的代码。

package com.pxl.test.Designpattern;
​
// 策略接口
interface DiscountStrategy {double applyDiscount(double totalPrice);
}
​
// 第一个具体策略类:无折扣
class NoDiscountStrategy implements DiscountStrategy {@Overridepublic double applyDiscount(double totalPrice) {return totalPrice;}
}
​
// 第二个具体策略类:固定折扣
class FixedDiscountStrategy implements DiscountStrategy {private double discountRate;
​public FixedDiscountStrategy(double discountRate) {this.discountRate = discountRate;}
​@Overridepublic double applyDiscount(double totalPrice) {return totalPrice - (totalPrice * discountRate);}
}
​
// 第三个具体策略类:满减折扣
class ThresholdDiscountStrategy implements DiscountStrategy {private double threshold;private double discountAmount;
​public ThresholdDiscountStrategy(double threshold, double discountAmount) {this.threshold = threshold;this.discountAmount = discountAmount;}
​@Overridepublic double applyDiscount(double totalPrice) {if (totalPrice >= threshold) {return totalPrice - discountAmount;}return totalPrice;}
}
​
// 上下文类,用于选择和应用具体的策略
class ShoppingCart {private DiscountStrategy discountStrategy;
​public ShoppingCart(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}
​public double checkout(double totalPrice) {return discountStrategy.applyDiscount(totalPrice);}
}
​
// 客户端代码
public class StrategyMain {public static void main(String[] args) {ShoppingCart cart1 = new ShoppingCart(new NoDiscountStrategy());ShoppingCart cart2 = new ShoppingCart(new FixedDiscountStrategy(0.1));ShoppingCart cart3 = new ShoppingCart(new ThresholdDiscountStrategy(100, 20));
​double totalPrice1 = 100;double totalPrice2 = 200;double totalPrice3 = 150;
​System.out.println("Cart 1 Total Price: " + cart1.checkout(totalPrice1));System.out.println("Cart 2 Total Price: " + cart2.checkout(totalPrice2));System.out.println("Cart 3 Total Price: " + cart3.checkout(totalPrice3));}
}
​

策略模式在Arrays中的使用

策略模式在Arraysp排序的时候使用到了策略模式。

分析:

Integer[] data = new Integer[]{3,2,1,5,4};Comparator<Integer> comparator = new Comparator<>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1 >= o2 ? 1 : -1;}};Arrays.sort(data,comparator);for (Integer datum : data) {System.out.print(datum + " ");}

上述代码就用到了策略,Arrays.sort(data,comparator);中的comparator采用了升序策略。

我们直接点击sort的源码

image-20240318165211304

小结

个人理解:策略模式是通过一个上下文类来聚合一个策略接口,并灵活的调用想要的策略。

策略模式通过将算法封装在独立的策略类中,并让上下文类持有一个策略接口的引用,实现了算法的灵活组合和调用。这种设计使得客户端可以根据需求选择并切换不同的策略,而不需要修改上下文类的代码,从而提高了代码的灵活性和可维护性。

作用:

  • 允许在运行时动态地选择算法。

  • 将算法的实现与使用它的客户端代码分离,提高了代码的灵活性和可维护性。

  • 通过使用接口和多态,实现了松耦合。

符合的原则:

  • 开闭原则(Open/Closed Principle):策略模式通过定义算法族,并使它们之间可以相互替换,从而在不修改原有代码的情况下添加新的算法。

  • 单一责任原则(Single Responsibility Principle):每个策略类只负责一个特定的算法或行为。

优点:

  1. 提供了更好的扩展性,可以轻松地添加新的算法或修改现有的算法。

  2. 提高了代码的可读性和可维护性,因为每个算法都被封装在一个独立的类中。

  3. 可以在运行时动态地选择算法,使得客户端代码更加灵活。

缺点:

  1. 增加了类的数量,可能会导致代码变得复杂。

  2. 客户端需要了解所有的策略类,可能会增加学习和理解的成本。

职责链模式(责任链模式)

可以理解职责链设计模式理解成一种链式处理请求的设计模式

介绍

1、职责链模式为请求创建一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦

2、职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依次类推。

image-20240318170701699

代码

image-20240318171547534

报销请求首先传递给经理(Manager),如果金额小于等于1000,则经理会直接批准;否则,请求会继续传递给部门主管(Department Supervisor),如果金额小于等于5000,则部门主管批准;否则,请求会继续传递给财务主管(Financial Manager)。

package com.pxl.test.Designpattern;
​
// 请求类
class ReimbursementRequest {private double amount;public ReimbursementRequest(double amount) {this.amount = amount;}public double getAmount() {return amount;}
}
​
// 处理者接口
interface Handler {void processRequest(ReimbursementRequest request);
}
​
// 具体处理者类
class Manager implements Handler {private Handler nextHandler;
​public Manager(Handler nextHandler) {this.nextHandler = nextHandler;}
​@Overridepublic void processRequest(ReimbursementRequest request) {if (request.getAmount() <= 1000) {System.out.println("Manager approves the reimbursement request.");} else {nextHandler.processRequest(request);}}
}
​
class DepartmentSupervisor implements Handler {private Handler nextHandler;
​public DepartmentSupervisor(Handler nextHandler) {this.nextHandler = nextHandler;}
​@Overridepublic void processRequest(ReimbursementRequest request) {if (request.getAmount() <= 5000) {System.out.println("Department Supervisor approves the reimbursement request.");} else {nextHandler.processRequest(request);}}
}
​
class FinancialManager implements Handler {@Overridepublic void processRequest(ReimbursementRequest request) {System.out.println("Financial Manager approves the reimbursement request.");}
}
​
// 客户端
public class ChainOfResponsibilityClient {public static void main(String[] args) {// 构建处理者链Handler financialManager = new FinancialManager();Handler departmentSupervisor = new DepartmentSupervisor(financialManager);Handler manager = new Manager(departmentSupervisor);
​// 创建报销请求ReimbursementRequest request1 = new ReimbursementRequest(800);ReimbursementRequest request2 = new ReimbursementRequest(3500);ReimbursementRequest request3 = new ReimbursementRequest(10000);
​// 发送请求manager.processRequest(request1);manager.processRequest(request2);manager.processRequest(request3);}
}
 

职责链模式在SpringMVC框架中的应用

在拦截器中使用到了。从核心类DispatcherServlet追。

职责链模式可以被理解为一种链式处理问题的解决方案。在职责链模式中,请求被传递到处理者链上的每个处理者,直到有一个处理者能够处理该请求为止。这种处理方式形成了一种链式的结构,因此被称为职责链模式。

总结

优点:

  1. 解耦性:请求的发送者和接收者之间解耦,发送者不需要知道具体的接收者。

  2. 可扩展性:可以方便地新增或调整处理者链,以满足不同的需求。

  3. 灵活性:可以动态地改变处理者链的顺序或组成,以满足不同的请求处理流程。

  4. 单一职责原则:每个处理者只需要关注自己能够处理的请求,不需要关注其他请求。

缺点:

  1. 请求可能未被处理:如果整条处理者链都不能处理请求,那么请求可能会未被处理。

  2. 性能问题:当处理者链过长时,可能会影响性能。

  3. 调试困难:由于请求的处理流程是动态的,因此调试起来可能会比较困难

 

这篇关于11种创造型设计模式(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/831501

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)

文章目录 1、工厂模式概述1)特点:2)主要角色:3)工作流程:4)优点5)缺点6)适用场景 2、简单工厂模式(静态工厂模式)1) 在简单工厂模式中,有三个主要角色:2) 简单工厂模式的优点包括:3) 简单工厂模式也有一些限制和考虑因素:4) 简单工厂模式适用场景:5) 简单工厂UML类图:6) 代码示例: 3、工厂方法模式1) 在工厂方法模式中,有4个主要角色:2) 工厂方法模式的工作流程

C#设计模式(1)——单例模式(讲解非常清楚)

一、引言 最近在学设计模式的一些内容,主要的参考书籍是《Head First 设计模式》,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二同时可以给一些初学设计模式的朋友一些参考。首先我介绍的是设计模式中比较简单的一个模式——单例模式(因为这里只牵涉到一个类) 二、单例模式的介绍 说到单例模式,大家第一

漫谈设计模式 [12]:模板方法模式

引导性开场 菜鸟:老大,我最近在做一个项目,遇到了点麻烦。我们有很多相似的操作流程,但每个流程的细节又有些不同。我写了很多重复的代码,感觉很乱。你有啥好办法吗? 老鸟:嗯,听起来你遇到了典型的代码复用和维护问题。你有没有听说过“模板方法模式”? 菜鸟:模板方法模式?没听过。这是什么? 老鸟:简单来说,模板方法模式让你在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。这样,你可

漫谈设计模式 [9]:外观模式

引导性开场 菜鸟:老鸟,我最近在做一个项目,感觉代码越来越复杂,我都快看不懂了。尤其是有好几个子系统,它们之间的调用关系让我头疼。 老鸟:复杂的代码确实让人头疼。你有没有考虑过使用设计模式来简化你的代码结构? 菜鸟:设计模式?我听说过一些,但不太了解。你觉得我应该用哪个模式呢? 老鸟:听起来你的问题可能适合用**外观模式(Facade Pattern)**来解决。我们可以一起探讨一下。

设计模式大全和详解,含Python代码例子

若有不理解,可以问一下这几个免费的AI网站 https://ai-to.cn/chathttp://m6z.cn/6arKdNhttp://m6z.cn/6b1quhhttp://m6z.cn/6wVAQGhttp://m6z.cn/63vlPw 下面是设计模式的简要介绍和 Python 代码示例,涵盖主要的创建型、结构型和行为型模式。 一、创建型模式 1. 单例模式 (Singleton

漫谈设计模式 [6]:适配器模式

引导性开场 菜鸟:老鸟,我最近在项目中遇到一个问题,我们的系统需要集成一个新的第三方库,但这个库的接口和我们现有的代码完全不兼容。我该怎么办? 老鸟:这是个常见的问题,很多开发者都会遇到这种情况。你有没有听说过适配器模式? 菜鸟:适配器模式?没有,能详细说说吗? 老鸟:当然可以!这就是我们今天要讨论的主题。适配器模式是一个设计模式,可以帮助我们解决你现在遇到的问题。 渐进式介绍概念 老

2 观察者模式(设计模式笔记)

2 观察者模式(别名:发布-订阅) 概念 定义对象间的一种一对多的依赖关系,当一个对象状态发生变化时,所以依赖于它的对象都得到通知并被自动更新。 模式的结构与使用 角色 主题(Subject)观察者(Observer)具体主题(ConcreteSubject)具体观察者(ConcreteObserver) 结构 Subject依赖于Observer最重要!!! package

1 单例模式(设计模式笔记)

1 单例模式 概述:使得一个类的对象成为系统中的唯一实例。 具体实现: 构造函数私有化 限制实例的个数 懒汉式(时间换空间) public class Singleton2 {public static Singleton2 singleton2;private Singleton2(){}public static Singleton2 getInstance() throws I

第三章 UML类图简介(设计模式笔记)

第三章 UML类图简介 3.1类 3.2接口 名字层必须有<> 3.3 泛化(继承)关系 箭头终点端指向父类(空心三角形) 3.4 关联(组合1)关系 B类是A类的成员变量 ,称A关联B。 箭头终点端指向B 3.5 依赖(组合2)关系 B类是A类的某个方法的参数 ,称A依赖B。 箭头终点端指向B(虚线) 3.6 实现关系 箭头终点端指向接口(虚线,空心