本文📚深入探讨了十一种行为型设计模式,如策略🎯、观察者👀和命令模式⚙️。每种模式均阐述了其目标🎯、适用场景🌍及案例分析🔍,并提供Java和Go语言的代码实现💻。这为软件开发者提供了理论与实践结合的宝贵资源🌟,帮助他们优化代码结构🛠️,提升软件的可维护性和灵活性,是理论与实战相结合的典范🏆。
行为型模式(Behavioral Patterns)
关注对象之间的责任分配,象之间如何通信、协作以完成特定任务,主要解决的是对象之间的责任分配和协作。
1、观察者模式(Observer)
- 目的:定义一种对象间的一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 应用场景:一个对象的改变需要同时改变其他对象,并且不知道具体有多少对象需要改变时;一个对象应该能够通知其他对象,而不需要知道这些对象是谁时;一个抽象模型有两个方面,其中一个方面依赖于另一个方面,但是两者又可以独立变化时。
- 案例:一个新闻订阅系统,新闻站点是被观察的主题,而订阅者是观察者。当新闻站点发布新的新闻时,所有订阅者都会收到通知并更新。
- 结构图:
Java实现
// Subject.java
// 订阅系统接口
interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String news);
}
// NewsStation.java
// 新闻主题
class NewsStation implements Subject {
private List<Observer> observers = new ArrayList<>();
private String latestNews;
public void setLatestNews(String news) {
this.latestNews = news;
notifyObservers(news);
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String news) {
for (Observer item : observers) {
item.update(news);
}
}
}
// Observer.java
// 观察者接口
interface Observer {
void update(String news);
}
// Subscriber.java
// 具体观察者
class Subscriber implements Observer {
private final String name;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String news) {
System.out.println(name + " 接受到最新的消息: " + news);
}
}
// Main.java
// 客户端
public class Main {
public static void main(String[] args) {
// 创建新闻站
NewsStation newsStation = new NewsStation();
// John注册
Observer subscriber1 = new Subscriber("John");
// Alice注册
Observer subscriber2 = new Subscriber("Alice");
// John订阅新闻
newsStation.addObserver(subscriber1);
// Alice订阅新闻
newsStation.addObserver(subscriber2);
// 模拟新闻发布
newsStation.setLatestNews("今年除夕不放假");
// Alice取消订阅
newsStation.removeObserver(Alice);
// 模拟新闻发布
newsStation.notifyObservers("2、除夕一起包饺子");
}
}
golang实现
package main
import (
"fmt"
"sync"
)
// 定义被观察者接口
type Subject interface {
addObserver(observer Observer) error
removeObserver(id string) error
notifyObservers(news string)
}
// 定义观察者接口
type Observer interface {
update(news string)
}
type NewsStation struct {
mutex sync.Mutex
observers map[string]Observer
latestNews string
}
func NewNewsStation() *NewsStation {
return &NewsStation{
observers: make(map[string]Observer),
}
}
func (n *NewsStation) addObserver(observer Observer, id string) error {
n.mutex.Lock()
defer n.mutex.Unlock()
if _, exists := n.observers[id]; exists {
return fmt.Errorf("id 为 '%s' 已存在", id)
}
n.observers[id] = observer
return nil
}
func (n *NewsStation) removeObserver(id string) error {
n.mutex.Lock()
defer n.mutex.Unlock()
if _, exists := n.observers[id]; !exists {
return fmt.Errorf("id 为 '%s' 不存在", id)
}
delete(n.observers, id)
return nil
}
func (n *NewsStation) notifyObservers(news string) {
n.mutex.Lock()
defer n.mutex.Unlock()
for _, observer := range n.observers {
observer.update(news)
}
}
// 观察者
type Subscriber struct {
name string
}
func NewSubscriber(name string) *Subscriber {
return &Subscriber{name: name}
}
func (s *Subscriber) update(news string) {
fmt.Printf("%s 接受到最新的消息: %s\n", s.name, news)
}
func main() {
// 新闻站
newsStation := NewNewsStation()
// john注册
john := NewSubscriber("john")
// alice注册
alice := NewSubscriber("alice")
// john关注新闻站
newsStation.addObserver(john, "john")
// alice关注新闻站
newsStation.addObserver(alice, "alice")
// 新闻站发送第一条消息
newsStation.notifyObservers("1、今年除夕不放假")
// alice取消关注新闻站
newsStation.removeObserver("alice")
// 新闻站发送第二条消息
newsStation.notifyObservers("2、除夕一起包饺子")
}
2、策略模式(Strategy)
- 目的:定义一系列算法,将每个算法封装起来,并使它们可以相互替换。客户端可以独立于具体的算法,并且可以轻松地切换算法,从而实现灵活的行为变化。
- 应用场景:当一个系统中有多个算法,且需要在运行时动态选择其中之一时,策略模式是一个合适的选择;当一个类有多个条件语句来选择不同的行为时,可以考虑使用策略模式来替代条件语句,提高可维护性;当不希望客户端依赖于具体算法实现,而是希望算法可以独立变化时,策略模式是一个有效的设计方案。
- 案例:个图像处理应用,其中有多种滤镜算法可以选择,例如黑白滤镜、模糊滤镜和反转色彩滤镜。使用策略模式可以使用户在运行时选择并切换不同的滤镜算法。
- 结构图:
Java实现
// ImageFilter.java
// 策略接口
interface ImageFilter {
void applyFilter(String imageName);
}
// BlackAndWhiteFilter.java
// 具体策略 - 黑白滤镜
class BlackAndWhiteFilter implements ImageFilter {
@Override
public void applyFilter(String imageName) {
System.out.println("使用黑白滤镜 " + imageName);
}
}
// BlurFilter.java
// 具体策略 - 模糊滤镜
class BlurFilter implements ImageFilter {
@Override
public void applyFilter(String imageName) {
System.out.println("使用模糊滤镜 " + imageName);
}
}
// InvertColorFilter.java
// 具体策略 - 反转色彩滤镜
class InvertColorFilter implements ImageFilter {
@Override
public void applyFilter(String imageName) {
System.out.println("使用反转色彩滤镜 " + imageName);
}
}
// ImageProcessor.java
// 上下文
class ImageProcessor {
private ImageFilter imageFilter;
public void setImageFilter(ImageFilter imageFilter) {
this.imageFilter = imageFilter;
}
public void processImage(String imageName) {
imageFilter.applyFilter(imageName);
}
}
// Main.java
// 客户端
public class Main {
public static void main(String[] args) {
ImageProcessor imageProcessor = new ImageProcessor();
// 使用黑白滤镜
imageProcessor.setImageFilter(new BlackAndWhiteFilter());
imageProcessor.processImage("image1.jpg");
// 切换为模糊滤镜
imageProcessor.setImageFilter(new BlurFilter());
imageProcessor.processImage("image2.jpg");
// 切换为反转色彩滤镜
imageProcessor.setImageFilter(new InvertColorFilter());
imageProcessor.processImage("image3.jpg");
}
}
golang实现
package main
import "fmt"
type ImageFilter interface {
applyFilter(imageName string)
}
type BlackAndWhiteFilter struct{}
func (b *BlackAndWhiteFilter) applyFilter(imageName string) {
fmt.Printf("使用黑白滤镜 %s\n", imageName)
}
type BlurFilter struct{}
func (b *BlurFilter) applyFilter(imageName string) {
fmt.Printf("使用模糊滤镜 %s\n", imageName)
}
type InvertColorFilter struct{}
func (i *InvertColorFilter) applyFilter(imageName string) {
fmt.Printf("使用反转色彩滤镜 %s\n", imageName)
}
type ImageProcessor struct {
imageFilter ImageFilter
}
func (i *ImageProcessor) setImageFilter(imageFilter ImageFilter) {
i.imageFilter = imageFilter
}
func (i *ImageProcessor) processImage(imageName string) {
i.imageFilter.applyFilter(imageName)
}
func main() {
imageProcessor := &ImageProcessor{}
// 使用黑白滤镜
imageProcessor.setImageFilter(&BlackAndWhiteFilter{})
imageProcessor.processImage("image1.jpg")
// 切换为模糊滤镜
imageProcessor.setImageFilter(&BlurFilter{})
imageProcessor.processImage("image2.jpg")
// 切换为模糊滤镜
imageProcessor.setImageFilter(&InvertColorFilter{})
imageProcessor.processImage("image3.jpg")
}
3、命令模式(Command)
- 目的:将请求封装成对象,从而使得客户端可以参数化队列,延迟请求的执行,或者将请求与接收者对象解耦。
- 应用场景:当希望将请求的发送者和接收者解耦时,可以使用命令模式。发送者不需要知道接收者的具体类,只需知道命令对象即可;当需要支持撤销(Undo)操作时,可以使用命令模式。每个命令对象可以存储执行前的状态,以便在需要时撤销操作。
- 案例:一个简单的遥控器应用,遥控器可以控制多个设备(例如电视、音响)并支持撤销操作。每个设备的操作都被封装成命令对象,遥控器通过调用这些命令对象来实现控制。
- 结构图:
Java实现
// 命令接口
interface Command {
void execute();
void undo();
}
// 具体命令 - 开启电视
class TurnOnTVCommand implements Command {
private TV tv;
public TurnOnTVCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOn();
}
@Override
public void undo() {
tv.turnOff();
}
}
// 具体命令 - 关闭电视
class TurnOffTVCommand implements Command {
private TV tv;
public TurnOffTVCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOff();
}
@Override
public void undo() {
tv.turnOn();
}
}
// 接收者 - 电视
class TV {
void turnOn() {
System.out.println("电视已开启");
}
void turnOff() {
System.out.println("电视已关闭");
}
}
// 调用者 - 遥控器
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
public void pressUndoButton() {
command.undo();
}
}
// 客户端
public class CommandPatternExample {
public static void main(String[] args) {
TV tv = new TV();
Command turnOnCommand = new TurnOnTVCommand(tv);
Command turnOffCommand = new TurnOffTVCommand(tv);
RemoteControl remoteControl = new RemoteControl();
// 开启电视
remoteControl.setCommand(turnOnCommand);
remoteControl.pressButton();
// 关闭电视
remoteControl.setCommand(turnOffCommand);
remoteControl.pressButton();
// 撤销操作
remoteControl.pressUndoButton();
}
}
golang实现
package main
import "fmt"
type TV struct{}
func (tv *TV) turnOn() {
fmt.Println("电视已开启")
}
func (tv *TV) turnOff() {
fmt.Println("电视已关闭")
}
type Command interface {
execute()
undo()
}
type TurnOffTVCommand struct {
tv TV
}
func (t *TurnOffTVCommand) execute() {
t.tv.turnOff()
}
func (t *TurnOffTVCommand) undo() {
t.tv.turnOn()
}
type TurnOnTVCommand struct {
tv TV
}
func (t *TurnOnTVCommand) execute() {
t.tv.turnOn()
}
func (t *TurnOnTVCommand) undo() {
t.tv.turnOff()
}
type RemoteControl struct {
command Command
}
func (r *RemoteControl) setCommand(command Command) {
r.command = command
}
func (r *RemoteControl) pressButton() {
r.command.execute()
}
func (r *RemoteControl) pressUndoButton() {
r.command.undo()
}
func main() {
tv := TV{}
turnOnTVCommand := &TurnOnTVCommand{tv: tv}
turnOffTVCommand := &TurnOffTVCommand{tv: tv}
remoteControl := &RemoteControl{}
// 开启电视机
remoteControl.setCommand(turnOnTVCommand)
remoteControl.pressButton()
// 关闭电视机
remoteControl.setCommand(turnOffTVCommand)
remoteControl.pressButton()
//撤销操作
remoteControl.pressUndoButton()
}
4、状态模式(State)
- 目的:允许一个对象在其内部状态发生改变时改变其行为,使其看起来好像修改了其类。状态模式将对象的状态封装成不同的类,使得在切换状态时能够轻松地改变对象的行为。
- 应用场景:当一个对象的行为取决于它的状态,并且需要在运行时根据状态改变行为时,可以使用状态模式; 当一个对象有很多状态,并且通过大量的条件语句来切换状态时,可以考虑使用状态模式来简化代码结构; 当对象的行为需要随着状态的变化而变化,而且状态之间有相互转换的关系时,使用状态模式可以使系统更加灵活。
- 案例:一个自动售货机的例子,其中自动售货机有多个状态,例如投币状态、选择商品状态、出货状态等。不同状态下,自动售货机的行为会有所不同。
Java实现
// VendingMachineState.java
// 状态接口
interface VendingMachineState {
void insertCoin();
void selectProduct();
void dispenseProduct();
}
// CoinInsertedState.java
// 具体状态 - 投币状态
class CoinInsertedState implements VendingMachineState {
@Override
public void insertCoin() {
System.out.println("已投币");
}
@Override
public void selectProduct() {
System.out.println("产品选择");
}
@Override
public void dispenseProduct() {
System.out.println("请先选择产品");
}
}
// ProductSelectedState.java
// 具体状态 - 选择商品状态
class ProductSelectedState implements VendingMachineState {
@Override
public void insertCoin() {
System.out.println("已投币");
}
@Override
public void selectProduct() {
System.out.println("产品以选择");
}
@Override
public void dispenseProduct() {
System.out.println("产品分配");
}
}
// 具体状态 - 出货状态
class ProductDispensedState implements VendingMachineState {
@Override
public void insertCoin() {
System.out.println("请稍等,正在分配产品");
}
@Override
public void selectProduct() {
System.out.println("产品以选择");
}
@Override
public void dispenseProduct() {
System.out.println("产品已配发,谢谢!");
}
}
// 上下文 - 自动售货机
class VendingMachine {
private VendingMachineState currentState;
public VendingMachine() {
currentState = new CoinInsertedState();
}
public void setCurrentState(VendingMachineState state) {
currentState = state;
}
public void insertCoin() {
currentState.insertCoin();
}
public void selectProduct() {
currentState.selectProduct();
}
public void dispenseProduct() {
currentState.dispenseProduct();
}
}
// 客户端
public class StatePatternExample {
public static void main(String[] args) {
VendingMachine vendingMachine = new VendingMachine();
vendingMachine.insertCoin();
vendingMachine.selectProduct();
vendingMachine.dispenseProduct();
}
}
golang实现
package main
import "fmt"
// 状态接口
type VendingMachineState interface {
InsertCoin(vm *VendingMachine)
SelectProduct(vm *VendingMachine)
DispenseProduct(vm *VendingMachine)
}
// 具体状态 - 投币状态
type CoinInsertedState struct{}
func (c *CoinInsertedState) InsertCoin(vm *VendingMachine) {
fmt.Println("已投币")
}
func (c *CoinInsertedState) SelectProduct(vm *VendingMachine) {
fmt.Println("产品选择")
vm.SetState(&ProductSelectedState{})
}
func (c *CoinInsertedState) DispenseProduct(vm *VendingMachine) {
fmt.Println("请先选择产品")
}
// 具体状态 - 选择商品状态
type ProductSelectedState struct{}
func (p *ProductSelectedState) InsertCoin(vm *VendingMachine) {
fmt.Println("已投币")
}
func (p *ProductSelectedState) SelectProduct(vm *VendingMachine) {
fmt.Println("产品已选择")
}
func (p *ProductSelectedState) DispenseProduct(vm *VendingMachine) {
fmt.Println("产品配发")
vm.SetState(&ProductDispensedState{})
}
// 具体状态 - 出货状态
type ProductDispensedState struct{}
func (p *ProductDispensedState) InsertCoin(vm *VendingMachine) {
fmt.Println("请稍等,正在分配产品")
}
func (p *ProductDispensedState) SelectProduct(vm *VendingMachine) {
fmt.Println("产品已选择")
}
func (p *ProductDispensedState) DispenseProduct(vm *VendingMachine) {
fmt.Println("产品已配发,谢谢!")
}
// 上下文 - 自动售货机
type VendingMachine struct {
currentState VendingMachineState
}
func (vm *VendingMachine) SetState(state VendingMachineState) {
vm.currentState = state
}
func (vm *VendingMachine) InsertCoin() {
vm.currentState.InsertCoin(vm)
}
func (vm *VendingMachine) SelectProduct() {
vm.currentState.SelectProduct(vm)
}
func (vm *VendingMachine) DispenseProduct() {
vm.currentState.DispenseProduct(vm)
}
// 客户端
func main() {
vendingMachine := &VendingMachine{currentState: &CoinInsertedState{}}
vendingMachine.InsertCoin()
vendingMachine.SelectProduct()
vendingMachine.DispenseProduct()
}
5、责任链模式(Chain of Responsibility)
- 目的:将请求的发送者和接收者解耦,并且使多个对象都有机会处理这个请求。责任链模式形成一条链,每个对象在收到请求后都会决定是否处理,以及是否将请求传递给下一个对象。
- 应用场景:当请求的发送者不需要知道请求被谁处理,以及处理的具体细节时,可以使用责任链模式; 当希望多个对象都有机会处理同一个请求时,可以使用责任链模式;当希望动态地指定处理流程时,可以使用责任链模式。通过动态地调整处理者之间的连接关系,可以实现灵活的处理流程。
- 案例:一个审批流程的例子,假设一个请假申请需要经过多个领导层级的审批。不同级别的领导可以是责任链中的不同处理者,每个领导负责判断是否能够批准该请假申请,如果不能,则将请求传递给下一级领导。
- 结构图
Java实现
// LeaveRequest.java
// 请求类
class LeaveRequest {
private String employee;
private int days;
public LeaveRequest(String employee, int days) {
this.employee = employee;
this.days = days;
}
public String getEmployee() {
return employee;
}
public int getDays() {
return days;
}
}
// Approver.java
// 处理者接口
interface Approver {
void processRequest(LeaveRequest request);
}
// Supervisor.java
// 具体处理者 - 直接主管
class Supervisor implements Approver {
private Approver nextApprover;
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 2) {
System.out.println("主管批准的员工休假申请: " + request.getEmployee());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
} else {
System.out.println("主管未批准的员工休假申请: " + request.getEmployee());
}
}
}
// DepartmentManager.java
// 具体处理者 - 部门经理
class DepartmentManager implements Approver {
private Approver nextApprover;
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 5) {
System.out.println("部门经理批准的员工休假申请: " + request.getEmployee());
} else if (nextApprover != null) {
nextApprover.processRequest(request);
} else {
System.out.println("部门经理未批准的员工休假申请: " + request.getEmployee());
}
}
}
// GeneralManager.java
// 具体处理者 - 总经理
class GeneralManager implements Approver {
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() > 5) {
System.out.println("总经理批准的员工休假申请: " + request.getEmployee());
} else {
System.out.println("总经理未批准的员工休假申请: " + request.getEmployee());
}
}
}
// Main.java
// 客户端
public class Main {
public static void main(String[] args) {
// 创建处理者对象
Supervisor supervisor = new Supervisor();
DepartmentManager departmentManager = new DepartmentManager();
GeneralManager generalManager = new GeneralManager();
// 设置处理者之间的关系
supervisor.setNextApprover(departmentManager);
departmentManager.setNextApprover(generalManager);
// 创建请假请求
LeaveRequest request1 = new LeaveRequest("John", 1);
LeaveRequest request2 = new LeaveRequest("Alice", 3);
LeaveRequest request3 = new LeaveRequest("Bob", 7);
// 处理请假请求
supervisor.processRequest(request1);
supervisor.processRequest(request2);
supervisor.processRequest(request3);
}
}
golang实现
package main
import "fmt"
type LeaveRequest struct {
employee string
days int
}
func NewLeaveRequest(employee string, days int) *LeaveRequest {
return &LeaveRequest{
employee: employee,
days: days,
}
}
type Approver interface {
processRequest(request LeaveRequest)
}
type Supervisor struct {
nextApprover Approver
}
func (s *Supervisor) processRequest(request LeaveRequest) {
if request.days <= 2 {
fmt.Printf("主管批准的员工休假申请:%d\n", request.days)
} else if s.nextApprover != nil {
s.nextApprover.processRequest(request)
} else {
fmt.Printf("主管未批准的员工休假申请:%d\n", request.days)
}
}
type DepartmentManager struct {
nextApprover Approver
}
func (s *DepartmentManager) processRequest(request LeaveRequest) {
if request.days <= 5 {
fmt.Printf("部门经理批准的员工休假申请:%d\n", request.days)
} else if s.nextApprover != nil {
s.nextApprover.processRequest(request)
} else {
fmt.Printf("部门经理未批准的员工休假申请:%d\n", request.days)
}
}
type GeneralManager struct {
nextApprover Approver
}
func (s *GeneralManager) processRequest(request LeaveRequest) {
if request.days > 5 {
fmt.Printf("总经理经理批准的员工休假申请:%d\n", request.days)
} else {
fmt.Printf("总经理未批准的员工休假申请:%d\n", request.days)
}
}
func main() {
// 创建处理者对象
supervisor := &Supervisor{}
departmentManager := &DepartmentManager{}
generalManager := &GeneralManager{}
// 设置处理者之间的关系
supervisor.nextApprover = departmentManager
departmentManager.nextApprover = generalManager
// 创建请假请求
request1 := LeaveRequest{employee: "John", days: 1}
request2 := LeaveRequest{employee: "Alice", days: 3}
request3 := LeaveRequest{employee: "Bob", days: 7}
supervisor.processRequest(request1)
supervisor.processRequest(request2)
supervisor.processRequest(request3)
}
6、访问者模式(Visitor)
- 目的:定义一种新的操作,而无需修改被操作的对象。通过在被访问的对象上添加一个接受访问者的方法,可以使对象在不改变自己的类结构的前提下,让外部类定义其操作。
- 应用场景:当有一个稳定的数据结构,但是需要对该数据结构进行多种不同的操作时,可以使用访问者模式;当类的结构经常发生变化,但对类的操作相对稳定时,可以使用访问者模式。
- 案例:一个图形库的例子,其中有不同类型的图形(如圆、矩形)和不同的操作(如绘制、移动)。使用访问者模式可以轻松地添加新的图形类型或操作,而不影响已有的类结构。
- 结构图
Java实现
// Shape.java
// 抽象元素 - 图形
interface Shape {
void accept(Visitor visitor);
}
// Circle.java
// 具体元素 - 圆
class Circle implements Shape {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// Rectangle.java
// 具体元素 - 矩形
class Rectangle implements Shape {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// Visitor.java
// 抽象访问者
interface Visitor {
void visit(Circle circle);
void visit(Rectangle rectangle);
}
// DrawVisitor.java
// 具体访问者 - 绘制操作
class DrawVisitor implements Visitor {
@Override
public void visit(Circle circle) {
System.out.println("Drawing Circle");
}
@Override
public void visit(Rectangle rectangle) {
System.out.println("Drawing Rectangle");
}
}
// MoveVisitor.java
// 具体访问者 - 移动操作
class MoveVisitor implements Visitor {
@Override
public void visit(Circle circle) {
System.out.println("Moving Circle");
}
@Override
public void visit(Rectangle rectangle) {
System.out.println("Moving Rectangle");
}
}
// Main.java
// 客户端
public class Main {
public static void main(String[] args) {
Shape circle = new Circle();
Shape rectangle = new Rectangle();
Visitor drawVisitor = new DrawVisitor();
Visitor moveVisitor = new MoveVisitor();
// 绘制操作
System.out.println("== 绘制操作 ==");
circle.accept(drawVisitor);
rectangle.accept(drawVisitor);
// 移动操作
System.out.println("== 移动操作 ==");
circle.accept(moveVisitor);
rectangle.accept(moveVisitor);
}
}
golang实现
package main
import "fmt"
type Shape interface {
accept(Visitor)
}
type Circle struct {
}
func (c *Circle) accept(visitor Visitor) {
visitor.visitCircle(c)
}
type Rectangle struct {
}
func (r *Rectangle) accept(visitor Visitor) {
visitor.visitRectangle(r)
}
type Visitor interface {
visitCircle(*Circle)
visitRectangle(*Rectangle)
}
type DrawVisitor struct{}
func (d *DrawVisitor) visitCircle(c *Circle) {
fmt.Println(" 绘制圆形 ")
}
func (d *DrawVisitor) visitRectangle(c *Rectangle) {
fmt.Println(" 绘制矩形 ")
}
type MoveVisitor struct{}
func (m *MoveVisitor) visitCircle(c *Circle) {
fmt.Println(" 移动圆形 ")
}
func (m *MoveVisitor) visitRectangle(c *Rectangle) {
fmt.Println(" 移动矩形 ")
}
func main() {
circle := &Circle{}
rectangle := &Rectangle{}
drawVisitor := &DrawVisitor{}
moveVisitor := &MoveVisitor{}
// 绘制操作
fmt.Println("== 绘制操作 ==")
circle.accept(drawVisitor)
rectangle.accept(drawVisitor)
// 移动操作
fmt.Println("== 移动操作 ==")
circle.accept(moveVisitor)
rectangle.accept(moveVisitor)
}
7、模板方法模式(Template Method)
- 目的:定义一个算法的骨架,将其中的某些步骤延迟到子类中实现。通过这种方式,模板方法模式使得算法的结构不变,但可以灵活地扩展和修改其中的某些步骤,而不影响整体算法的结构。
- 应用场景:当一个算法的整体结构已经确定,但其中的某些步骤可能由于应用的不同而变化时;多个类中存在相似的算法流程,可以将这些流程提取到一个公共的父类中,减少代码重复,提高代码的可维护性;在框架设计中,模板方法模式经常被用于定义框架的基本流程,而将一些具体实现留给子类来完成。
- 案例:一个炒菜的例子,炒菜的步骤包括加热油、放入食材、翻炒等。这些步骤的顺序在不同的炒菜中可能有所不同。模板方法模式可以定义一个炒菜的模板,具体的炒菜类只需实现其中的具体步骤。
Java实现
// CookingTemplate.java
// 抽象类 - 炒菜模板
abstract class CookingTemplate {
// 模板方法
public final void cook() {
heatOil();
addIngredients();
stirFry();
serve();
}
// 具体步骤1 - 加热油
protected void heatOil() {
System.out.println("热油");
}
// 具体步骤2 - 放入食材
protected abstract void addIngredients();
// 具体步骤3 - 翻炒
protected void stirFry() {
System.out.println("翻炒");
}
// 具体步骤4 - 上菜
protected void serve() {
System.out.println("上菜");
}
}
// GreenPepperBeefCooking.java
// 具体类 - 青椒炒肉
class GreenPepperBeefCooking extends CookingTemplate {
@Override
protected void addIngredients() {
System.out.println("放入青椒和牛肉");
}
}
// KungPaoChickenCooking.java
// 具体类 - 宫保鸡丁
class KungPaoChickenCooking extends CookingTemplate {
@Override
protected void addIngredients() {
System.out.println("放入鸡肉、花生和辣椒");
}
}
// Main.java
// 客户端
public class Main {
public static void main(String[] args) {
CookingTemplate greenPepperBeef = new GreenPepperBeefCooking();
CookingTemplate kungPaoChicken = new KungPaoChickenCooking();
// 使用模板方法炒青椒肉
greenPepperBeef.cook();
System.out.println("------------------");
// 使用模板方法炒宫保鸡丁
kungPaoChicken.cook();
}
}
golang实现
package main
import "fmt"
// CookingProcess 定义炒菜的接口
type CookingProcess interface {
HeatOil()
AddMainIngredients()
StirFry()
Serve()
}
// CookingTemplate 提供了一个模板方法
type CookingTemplate struct {
process CookingProcess
}
func (c *CookingTemplate) Cook() {
c.process.HeatOil()
c.process.AddMainIngredients()
c.process.StirFry()
c.process.Serve()
}
// GreenPepperBeef 实现 CookingProcess 接口
type GreenPepperBeef struct{}
func (g *GreenPepperBeef) HeatOil() {
fmt.Println("热油")
}
func (g *GreenPepperBeef) AddMainIngredients() {
fmt.Println("放入青椒和牛肉")
}
func (g *GreenPepperBeef) StirFry() {
fmt.Println("翻炒")
}
func (g *GreenPepperBeef) Serve() {
fmt.Println("上菜")
}
// KungPaoChicken 实现 CookingProcess 接口
type KungPaoChicken struct{}
func (k *KungPaoChicken) HeatOil() {
fmt.Println("热油")
}
func (k *KungPaoChicken) AddMainIngredients() {
fmt.Println("放入鸡肉、花生和辣椒")
}
func (k *KungPaoChicken) StirFry() {
fmt.Println("翻炒")
}
func (k *KungPaoChicken) Serve() {
fmt.Println("上菜")
}
func main() {
greenPepperBeef := &GreenPepperBeef{}
kungPaoChicken := &KungPaoChicken{}
greenPepperBeefTemplate := CookingTemplate{greenPepperBeef}
kungPaoChickenTemplate := CookingTemplate{kungPaoChicken}
// 使用模板方法炒青椒肉
greenPepperBeefTemplate.Cook()
fmt.Println("------------------")
// 使用模板方法炒宫保鸡丁
kungPaoChickenTemplate.Cook()
}
8、中介者模式(Mediator)
- 目的:减少组件之间的直接通信,而是通过一个中介者对象进行通信。通过引入中介者,组件之间不需要直接知道彼此,而是通过中介者进行协调和通信,从而降低了组件之间的耦合度。
- 应用场景:中介者模式有助于实现组件之间的松散耦合,使得系统更易于扩展和维护。
- 案例:一个聊天室的例,在聊天室中,多个用户之间需要相互通信,但不希望每个用户都直接与其他用户通信。通过引入中介者,用户可以通过中介者进行消息的发布和接收,而不需要直接知道其他用户的存在。
- 结构图
Java实现
// ChatMediator.java
// 中介者接口
interface ChatMediator {
void sendMessage(String message, User user);
void addUser(User user);
}
// ChatMediatorImpl.java
// 具体中介者
class ChatMediatorImpl implements ChatMediator {
private List<User> users;
public ChatMediatorImpl() {
this.users = new ArrayList<>();
}
@Override
public void sendMessage(String message, User user) {
for (User item : users) {
// 发送消息给其他用户(排除发送者本身)
if (item != user) {
item.receiveMessage(message);
}
}
}
@Override
public void addUser(User user) {
users.add(user);
}
}
// User.java
// 抽象用户类
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void sendMessage(String message);
public abstract void receiveMessage(String message);
}
// User.java
// 具体用户类
class ChatUser extends User {
public ChatUser(ChatMediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendMessage(String message) {
System.out.println(name + " 发送消息: " + message);
mediator.sendMessage(message, this);
}
@Override
public void receiveMessage(String message) {
System.out.println(name + " 收到消息: " + message);
}
}
public class Main {
public static void main(String[] args) {
ChatMediator mediator = new ChatMediatorImpl();
User user1 = new ChatUser(mediator, "User1");
User user2 = new ChatUser(mediator, "User2");
User user3 = new ChatUser(mediator, "User3");
mediator.addUser(user1);
mediator.addUser(user2);
mediator.addUser(user3);
user1.sendMessage("Hello, everyone!");
}
}
golang实现
package main
import "fmt"
// 中介者接口
type ChatMediator interface {
SendMessage(message string, user *User)
}
// 具体中介者
type ChatMediatorImpl struct {
users []*User
}
func NewChatMediator() *ChatMediatorImpl {
return &ChatMediatorImpl{users: make([]*User, 0)}
}
func (c *ChatMediatorImpl) AddUser(user *User) {
c.users = append(c.users, user)
}
func (c *ChatMediatorImpl) SendMessage(message string, user *User) {
for _, u := range c.users {
if u != user {
u.ReceiveMessage(message)
}
}
}
// 用户结构体
type User struct {
mediator ChatMediator
name string
}
func NewUser(mediator ChatMediator, name string) *User {
return &User{mediator: mediator, name: name}
}
func (u *User) SendMessage(message string) {
fmt.Printf("%s 发送消息: %s\n", u.name, message)
u.mediator.SendMessage(message, u)
}
func (u *User) ReceiveMessage(message string) {
fmt.Printf("%s 收到消息: %s\n", u.name, message)
}
func main() {
mediator := NewChatMediator()
user1 := NewUser(mediator, "User1")
user2 := NewUser(mediator, "User2")
user3 := NewUser(mediator, "User3")
mediator.AddUser(user1)
mediator.AddUser(user2)
mediator.AddUser(user3)
user1.SendMessage("Hello, everyone!")
}
9、备忘录模式(Memento)
- 目的:在不破坏封装的前提下,捕获一个对象的内部状态,以便后续恢复对象到这个状态。这种模式通常用于需要提供撤销(Undo)操作的场景,或者需要在某个时刻记录对象的状态,以便之后进行还原。
- 应用场景:在数据库或事务管理系统中,备忘录模式可以用于记录事务的状态,以便在发生错误时回滚到先前的状态;在游戏中,备忘录模式可以用于保存玩家的游戏进度,以便在需要时恢复到之前的状态。
- 案例:一个文本编辑器的例子,用户可以输入文本并执行撤销操作。备忘录模式可以用于保存文本编辑器的历史状态,以便用户可以撤销到先前的编辑状态。
Java实现
import java.util.ArrayList;
import java.util.List;
// Memento.java
// 备忘录类
class Memento {
private final String state;
Memento(String state) {
this.state = state;
}
String getState() {
return state;
}
}
// TextEditor.java
// 原发器类
class TextEditor {
private String content;
void setContent(String content) {
this.content = content;
}
String getContent() {
return content;
}
Memento save() {
return new Memento(content);
}
void undoToLastSave(Object obj) {
if (obj instanceof Memento) {
Memento memento = (Memento) obj;
content = memento.getState();
}
}
}
// Caretaker.java
// 负责人类
class Caretaker {
private final List<Memento> savedStates = new ArrayList<>();
void addMemento(Memento m) {
savedStates.add(m);
}
Memento getMemento(int index) {
return savedStates.get(index);
}
}
// Main.java
public class Main {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
Caretaker caretaker = new Caretaker();
editor.setContent("State #1");
editor.setContent("State #2");
caretaker.addMemento(editor.save());
editor.setContent("State #3");
caretaker.addMemento(editor.save());
editor.setContent("State #4");
editor.undoToLastSave(caretaker.getMemento(1));
System.out.println("当前内容: " + editor.getContent());
editor.undoToLastSave(caretaker.getMemento(0));
System.out.println("当前内容: " + editor.getContent());
}
}
golang实现
package main
import "fmt"
// 备忘录类
type Memento struct {
state string
}
// 原发器类
type TextEditor struct {
content string
}
func (t *TextEditor) SetContent(content string) {
t.content = content
}
func (t *TextEditor) GetContent() string {
return t.content
}
func (t *TextEditor) Save() *Memento {
return &Memento{state: t.content}
}
func (t *TextEditor) UndoToLastSave(m *Memento) {
t.content = m.state
}
// 负责人类
type Caretaker struct {
mementos []*Memento
}
func (c *Caretaker) AddMemento(m *Memento) {
c.mementos = append(c.mementos, m)
}
func (c *Caretaker) GetMemento(index int) *Memento {
return c.mementos[index]
}
func main() {
editor := &TextEditor{}
caretaker := &Caretaker{}
editor.SetContent("State #1")
editor.SetContent("State #2")
caretaker.AddMemento(editor.Save())
editor.SetContent("State #3")
caretaker.AddMemento(editor.Save())
editor.SetContent("State #4")
editor.UndoToLastSave(caretaker.GetMemento(1))
fmt.Println("当前内容:", editor.GetContent())
editor.UndoToLastSave(caretaker.GetMemento(0))
fmt.Println("当前内容:", editor.GetContent())
}
10、解释器模式(Interpreter)
- 目的:定义一种语言的文法,并在这个语言中解释句子的意义。
- 应用场景:解决一些特定类型的问题,例如编译器、正则表达式解析、自然语言处理等。
- 案例:用解释器模式实现一个简单的布尔逻辑解释器,解释器可以解析和计算像 true AND false 或 true OR (false AND true) 这样的布尔表达式。
- 结构图:
Java实现
// Expression.java
// 抽象表达式接口
interface Expression {
boolean interpret(Context context);
}
// VariableExpression.java
// 终结符表达式
class VariableExpression implements Expression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public boolean interpret(Context context) {
return context.lookup(name);
}
}
// AndExpression.java
// 非终结符表达式 - AND
class AndExpression implements Expression {
private Expression expr1;
private Expression expr2;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(Context context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
// OrExpression.java
// 非终结符表达式 - OR
class OrExpression implements Expression {
private Expression expr1;
private Expression expr2;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(Context context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
// Context.java
// 上下文类,用于变量赋值
class Context {
private Map<String, Boolean> variables = new HashMap<>();
public void assign(String var, boolean value) {
variables.put(var, value);
}
public boolean lookup(String var) {
return variables.getOrDefault(var, false);
}
}
// Main.java
// 客户端使用
public class Main {
public static void main(String[] args) {
// 构建布尔表达式 (true AND false) OR (false AND true)
Expression expr = new OrExpression(
new AndExpression(new VariableExpression("X"), new VariableExpression("Y")),
new AndExpression(new VariableExpression("A"), new VariableExpression("B"))
);
Context context = new Context();
context.assign("X", true);
context.assign("Y", false);
context.assign("A", false);
context.assign("B", true);
boolean result = expr.interpret(context);
System.out.println("Result: " + result);
}
}
golang实现
package main
import "fmt"
type Expression interface {
interpret(Context) bool
}
type VariableExpression struct {
name string
}
func (v *VariableExpression) interpret(context Context) bool {
return context.lookup(v.name)
}
type AndExpression struct {
expr1 Expression
expr2 Expression
}
func (a *AndExpression) interpret(context Context) bool {
return a.expr1.interpret(context) && a.expr2.interpret(context)
}
type OrExpression struct {
expr1 Expression
expr2 Expression
}
func (a *OrExpression) interpret(context Context) bool {
return a.expr1.interpret(context) || a.expr2.interpret(context)
}
type Context struct {
variables map[string]bool
}
func NewContext() *Context {
return &Context{
variables: make(map[string]bool, 8),
}
}
func (c *Context) assign(key string, value bool) {
c.variables[key] = value
}
func (c *Context) lookup(key string) bool {
return c.variables[key]
}
func main() {
// 构建布尔表达式 (true AND false) OR (true AND true)
expr := &OrExpression{
expr1: &AndExpression{expr1: &VariableExpression{name: "X"}, expr2: &VariableExpression{name: "Y"}},
expr2: &AndExpression{expr1: &VariableExpression{name: "A"}, expr2: &VariableExpression{name: "B"}},
}
context := NewContext()
context.assign("X", true)
context.assign("Y", false)
context.assign("A", true)
context.assign("B", true)
res := expr.interpret(*context)
fmt.Printf("result : %v", res)
}
11、迭代器模式(Iterator)
- 目的:提供一种访问集合元素的统一接口,而不暴露底层集合的实现细节。它属于行为型模式,通过定义一个迭代器接口,客户端可以遍历集合而不必关心底层数据结构。
- 应用场景:集合类的遍历,不同集合类型的统一访问。
- 案例:一个图书馆的书籍管理系统,其中包含不同类型的书籍,例如小说、科普书、艺术书等。使用迭代器模式可以实现一个统一的接口,用于遍历图书馆中的不同类型的书籍。
Java实现
// Book.java
// 书籍类
class Book {
private String title;
public Book(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
// Library.java
// 书籍集合类
class Library implements Iterable<Book> {
private List<Book> books;
public Library() {
this.books = new ArrayList<>();
}
public void addBook(Book book) {
books.add(book);
}
@Override
public Iterator<Book> iterator() {
return new BookIterator();
}
// 内部迭代器类
private class BookIterator implements Iterator<Book> {
private int index = 0;
@Override
public boolean hasNext() {
return index < books.size();
}
@Override
public Book next() {
return books.get(index++);
}
}
}
// Main.java
// 客户端使用
public class Main {
public static void main(String[] args) {
Library library = new Library();
library.addBook(new Book("Java Programming"));
library.addBook(new Book("Design Patterns"));
library.addBook(new Book("Artificial Intelligence"));
// 使用迭代器遍历书籍集合
Iterator<Book> iterator = library.iterator();
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println("Book Title: " + book.getTitle());
}
}
}
golang实现
package main
import (
"fmt"
)
// Book 结构表示书籍
type Book struct {
title string
}
// Library 结构表示图书馆
type Library struct {
books []Book
}
// Iterator 接口表示迭代器
type Iterator interface {
HasNext() bool
Next() Book
}
// BookIterator 结构实现 Iterator 接口
type BookIterator struct {
library *Library
index int
}
func (bi *BookIterator) HasNext() bool {
return bi.index < len(bi.library.books)
}
func (bi *BookIterator) Next() Book {
book := bi.library.books[bi.index]
bi.index++
return book
}
// NewBookIterator 返回一个 BookIterator 实例
func NewBookIterator(library *Library) Iterator {
return &BookIterator{library: library, index: 0}
}
// NewLibrary 返回一个 Library 实例
func NewLibrary() *Library {
return &Library{books: make([]Book, 0)}
}
// AddBook 向图书馆中添加书籍
func (l *Library) AddBook(book Book) {
l.books = append(l.books, book)
}
func main() {
library := NewLibrary()
library.AddBook(Book{"Java Programming"})
library.AddBook(Book{"Design Patterns"})
library.AddBook(Book{"Artificial Intelligence"})
// 使用迭代器遍历书籍集合
iterator := NewBookIterator(library)
for iterator.HasNext() {
book := iterator.Next()
fmt.Println("Book Title:", book.title)
}
}