设计模式,作为一套广泛认可的解决方案,专门用于应对特定的编程难题。它们将复杂逻辑优雅地解耦,增强代码的灵活性和可维护性。
设计模式
设计模式是在软件设计中反复出现的问题的经验性解决方案。这些解决方案是经过时间测试和验证的,可以在特定的上下文中应用,以解决通常会在软件设计和开发过程中遇到的一些常见问题。设计模式提供了一种通用的、可重用的解决方案,有助于构建更灵活、可维护和可扩展的软件系统。
设计模式并不是一种具体的代码实现,而是一种抽象的思想和指导原则,开发者可以根据这些原则来构建满足特定需求的具体代码。设计模式的使用有助于提高代码的可读性、可维护性和可重用性,同时可以促使开发者以更系统化和标准化的方式进行软件设计。
常见的设计模式可以分为三大类:
- 创建型模式(Creational Patterns)(5种): 关注对象的创建过程,包括单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式等。
- 结构型模式(Structural Patterns)(7种): 关注如何组合类和对象以构建更大的结构,包括适配器模式、装饰者模式、代理模式、桥接模式、组合模式、外观模式、享元模式等。
- 行为型模式(Behavioral Patterns)(11种): 关注对象之间的通信和责任分配,包括观察者模式、策略模式、命令模式、状态模式、责任链模式、访问者模式、模板方法模式、中介者模式、备忘录模式、解释器模式、迭代器模式等。
设计模式优点
- 代码重用性: 设计模式提供了经过验证和优化的解决方案,可以在不同的项目和场景中重复使用。这有助于减少代码重复,提高代码的可维护性和可扩展性。
- 代码可读性: 使用设计模式可以使代码更易于理解和阅读。设计模式通常使用一种标准化的方式来解决特定类型的问题,使得代码结构更加清晰,降低了代码的复杂性。
- 团队协作: 设计模式提供了一种共享的设计语言,可以促进团队之间的沟通。当团队成员熟悉常见的设计模式时,他们能够更容易地理解和交流彼此的设计选择。
- 可维护性: 使用设计模式可以提高代码的可维护性。由于设计模式强调松耦合和模块化,当需要修改或扩展功能时,只需关注特定的模块而不是整个代码库。
- 问题解决能力: 学习设计模式有助于培养抽象思维和问题解决的能力。设计模式提供了一种框架,可以应对各种常见的软件设计问题,帮助开发人员更好地理解和解决复杂的系统设计挑战。
学习设计模式是提高软件设计和开发水平的有效途径,可以帮助开发人员写出更健壮、可维护和可扩展的代码。
创建型模式(Creational Patterns)
关注对象的创建过程,旨在提供一种灵活的方法来实例化对象。这些模式都涉及到将对象的创建和初始化过程封装起来,使系统更加灵活、松散耦合,同时更容易扩展。
1、单例模式(Singleton)
- 目的:确保一个类只有一个实例,并提供一个全局访问点。
- 应用场景: 用于需要共享资源的场景,如数据库连接、日志记录等。
- 案例:假设有一个配置管理器类ConfigManager,它负责加载和维护一些系统配置。由于配置信息通常在整个应用程序中是统一且唯一的,因此这个类的实例应该只有一个,以确保整个应用程序使用的是相同的配置信息。
Java实现
// ConfigManager.java
public class ConfigManager {
// 创建一个ConfigManager类型的私有静态实例
private static ConfigManager instance;
// 私有化构造函数,防止外部通过new创建多个实例
private ConfigManager() {
// 初始化配置信息
}
// 提供一个公共的静态方法,用于获取唯一的实例
public static ConfigManager getInstance() {
// 双重检查锁定
if (instance == null) {
synchronized (ConfigManager.class) {
if (instance == null) {
instance = new ConfigManager();
}
}
}
return instance;
}
// 其他业务方法
public void loadConfig() {
// 加载配置信息的方法
}
}
// Main.java
// 使用方式
public class Main {
public static void main(String[] args) {
ConfigManager configManager = ConfigManager.getInstance();
configManager.loadConfig();
// todo 从这里开始,可以使用配置信息
// 通过单例模式获取两个实例
// ConfigManager instance1 = ConfigManager.getInstance();
// ConfigManager instance2 = ConfigManager.getInstance();
// // 检查两个实例的引用是否相同
// if (instance1 == instance2) {
// System.out.println("instance1 和 instance2 是同一个实例。");
// } else {
// System.out.println("instance1 和 instance2 不是同一个实例。");
// }
}
}
golang实现
package singleton
import (
"sync"
)
// 定义单例类型
type singleton struct {
// 这里可以包含单例的状态
}
// 私有的单例变量
var instance *singleton
var once sync.Once
// 获取单例对象的公共方法
func GetInstance() *singleton {
// 只执行一次的确保单例实例化
once.Do(func() {
instance = &singleton{}
})
return instance
}
// 使用方式
package main
import (
"fmt"
"singleton"
)
func main() {
// 获取单例实例
instance1 := singleton.GetInstance()
instance2 := singleton.GetInstance()
// 检查两个实例是否相同
if instance1 == instance2 {
fmt.Println("instance1 和 instance2 是同一个实例。")
} else {
fmt.Println("instance1 和 instance2 不是同一个实例。")
}
}
2、工厂方法模式(Factory Method)
- 目的:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
- 应用场景:当一个类希望其子类来指定创建的对象时。
- 案例:设计一个日志记录器的应用,它可以将日志记录到不同的地方,比如文件、数据库或者网络。定义一个日志记录器接口和一系列实现这个接口的具体日志记录器。使用工厂方法模式来创建具体的日志记录器实例,而不是直接在代码中实例化这些记录器。
- 案例对象图

- Java实现
// Logger.java
// 日志记录器接口
public interface Logger {
void log(String message);
}
// FileLogger.java
// 文件日志记录器
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("File logger: " + message);
}
}
// DatabaseLogger.java
// 数据库日志记录器
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Database logger: " + message);
}
}
// NetworkLogger.java
// 网络日志记录器
public class NetworkLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Network logger: " + message);
}
}
// LoggerFactory.java
// 日志记录器工厂接口
public abstract class LoggerFactory {
private Logger logger = null;
// 工厂方法
public abstract Logger createLogger();
// 工厂方法调用示例
public void logMessage(String message) {
// 如果logger未被创建,那么创建它
if (logger == null) {
logger = createLogger();
}
logger.log(message);
}
}
// FileLoggerFactory.java
// 文件日志记录器工厂
public class FileLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
// 创建文件日志记录器
return new FileLogger();
}
}
// DatabaseLoggerFactory.java
// 数据库日志记录器工厂
public class DatabaseLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
// 创建数据库日志记录器
return new DatabaseLogger();
}
}
// NetworkLoggerFactory.java
// 网络日志记录器工厂
public class NetworkLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
// 创建网络日志记录器
return new NetworkLogger();
}
}
// Main.java
// 使用
public class Main {
public static void main(String[] args) {
LoggerFactory factory;
factory = new FileLoggerFactory();
factory.logMessage("This is a file log message.");
factory = new DatabaseLoggerFactory();
factory.logMessage("This is a database log message.");
factory = new NetworkLoggerFactory();
factory.logMessage("This is a network log message.");
}
}
- golang实现
package logger
// Logger 是所有日志记录器必须实现的接口
type Logger interface {
Log(message string)
}
// FileLogger 是一个日志记录器的实现,它将日志写入文件
type FileLogger struct{}
func (l *FileLogger) Log(message string) {
// 这里将消息写入文件
fmt.Println("File logger: ", message)
}
// DatabaseLogger 是一个日志记录器的实现,它将日志写入数据库
type DatabaseLogger struct{}
func (l *DatabaseLogger) Log(message string) {
// 这里将消息写入数据库
fmt.Println("Database logger: ", message)
}
// NetworkLogger 是一个日志记录器的实现,它通过网络发送日志
type NetworkLogger struct{}
func (l *NetworkLogger) Log(message string) {
// 这里将消息发送到网络
fmt.Println("Network logger: ", message)
}
package logger
// LoggerType 定义了可能的日志记录器类型
type LoggerType int
const (
File LoggerType = iota
Database
Network
)
// GetLogger 是工厂方法,返回一个 Logger 接口
func GetLogger(t LoggerType) Logger {
switch t {
case File:
return &FileLogger{}
case Database:
return &DatabaseLogger{}
case Network:
return &NetworkLogger{}
default:
return nil
}
}
package main
import (
"logger"
)
func main() {
fileLogger := logger.GetLogger(logger.File)
fileLogger.Log("This is a file log message.")
dbLogger := logger.GetLogger(logger.Database)
dbLogger.Log("This is a database log message.")
netLogger := logger.GetLogger(logger.Network)
netLogger.Log("This is a network log message.")
}
3、抽象工厂模式(Abstract Factory)
- 目的:创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
- 应用场景:当需要创建一系列相关的对象,且不想暴露其具体实现时。
- 案例:设计一个支付系统,不同的支付方式(例如信用卡、支付宝、微信支付)都有不同的实现方式,但系统需要对这些支付方式进行统一的处理。
- 案例对象图

- Java & golang实现
// PaymentProcessor.java
// 支付接口
public interface PaymentProcessor {
void processPayment(String amount);
}
// AlipayProcessor.java
// 支付宝支付
public class AlipayProcessor implements PaymentProcessor {
@Override
public void processPayment(String amount) {
System.out.println("Processing Alipay payment for: " + amount);
}
}
// WeChatProcessor.java
// 微信支付
public class WeChatProcessor implements PaymentProcessor {
@Override
public void processPayment(String amount) {
System.out.println("Processing WeChat payment for: " + amount);
}
}
// CreditCardProcessor.java
// 信用卡支付
public class CreditCardProcessor implements PaymentProcessor {
@Override
public void processPayment(String amount) {
System.out.println("Processing credit card payment for: " + amount);
}
}
// PaymentFactory.java
// 支付工厂接口
public interface PaymentFactory {
PaymentProcessor createProcessor();
}
// AlipayPaymentFactory.java
// 支付宝支付工厂
public class AlipayPaymentFactory implements PaymentFactory {
@Override
public PaymentProcessor createProcessor() {
return new AlipayProcessor();
}
}
// WeChatPaymentFactory.java
// 微信支付工厂
public class WeChatPaymentFactory implements PaymentFactory {
@Override
public PaymentProcessor createProcessor() {
return new WeChatProcessor();
}
}
// CreditCardPaymentFactory.java
// 信用卡支付工厂
public class CreditCardPaymentFactory implements PaymentFactory {
@Override
public PaymentProcessor createProcessor() {
return new CreditCardProcessor();
}
}
// PaymentService.java
public class PaymentService {
private final PaymentFactory paymentFactory;
public PaymentService(PaymentFactory paymentFactory) {
this.paymentFactory = paymentFactory;
}
public void makePayment(String amount) {
PaymentProcessor processor = paymentFactory.createProcessor();
processor.processPayment(amount);
}
}
// 使用
// Main.java
public class Main {
public static void main(String[] args) {
PaymentFactory creditCardFactory = new CreditCardPaymentFactory();
PaymentFactory alipayFactory = new AlipayPaymentFactory();
PaymentFactory weChatFactory = new WeChatPaymentFactory();
PaymentService creditCardService = new PaymentService(creditCardFactory);
creditCardService.makePayment("1000");
PaymentService alipayService = new PaymentService(alipayFactory);
alipayService.makePayment("2000");
PaymentService weChatService = new PaymentService(weChatFactory);
weChatService.makePayment("3000");
}
}
package main
import "fmt"
// PaymentProcessor 定义支付方式的接口
type PaymentProcessor interface {
ProcessPayment(amount string)
}
// Alipay 支付宝支付
type AlipayProcessor struct{}
func (p *AlipayProcessor) ProcessPayment(amount string) {
fmt.Println("Processing Alipay payment for:", amount)
}
// WeChatPay 微信支付
type WeChatProcessor struct{}
func (p *WeChatProcessor) ProcessPayment(amount string) {
fmt.Println("Processing WeChat payment for:", amount)
}
// CreditCard 信用卡支付
type CreditCardProcessor struct{}
func (p *CreditCardProcessor) ProcessPayment(amount string) {
fmt.Println("Processing credit card payment for:", amount)
}
// PaymentFactory 是创建支付方式的工厂接口
type PaymentFactory interface {
CreateProcessor() PaymentProcessor
}
// 具体的支付宝支付工厂
type AlipayFactory struct{}
type AlipayPaymentFactory struct{}
func (f AlipayPaymentFactory) CreateProcessor() PaymentProcessor {
return &AlipayProcessor{}
}
// 具体的微信支付工厂
type WeChatPaymentFactory struct{}
func (w *WeChatPaymentFactory) CreateProcessor() PaymentProcessor {
return &WeChatProcessor{}
}
// 具体的信用卡支付工厂
type CreditCardPaymentFactory struct{}
func (c *CreditCardPaymentFactory) CreateProcessor() PaymentProcessor {
return &CreditCardProcessor{}
}
type PaymentService struct {
factory PaymentFactory
}
func NewPaymentService(factory PaymentFactory) *PaymentService {
return &PaymentService{factory: factory}
}
func (s *PaymentService) MakePayment(amount string) {
processor := s.factory.CreateProcessor()
processor.ProcessPayment(amount)
}
func main() {
creditCardFactory := &CreditCardPaymentFactory{}
alipayFactory := &AlipayPaymentFactory{}
weChatFactory := &WeChatPaymentFactory{}
creditCardService := NewPaymentService(creditCardFactory)
creditCardService.MakePayment("1000")
alipayService := NewPaymentService(alipayFactory)
alipayService.MakePayment("2000")
weChatService := NewPaymentService(weChatFactory)
weChatService.MakePayment("3000")
}
4、建造者模式(Builder)
- 目的:将一个复杂对象的构建与其表示分离,以便相同的构建过程可以创建不同的表示。
- 应用场景:当创建复杂对象的算法应独立于该对象的组成部分以及它们的装配方式时。
- 案例:构建一个复杂的Computer对象,它包含多个部件,如CPU、RAM、硬盘和显卡等。这些部件在不同的计算机中可能会有不同的配置。使用建造者模式可以灵活地构建各种不同配置的计算机。
- Java实现
// Computer.java
public class Computer {
// Computer的各个部件
private String CPU;
private String RAM;
private String hardDisk;
private String graphicsCard;
// 私有的构造函数,防止直接实例化
private Computer(Builder builder) {
this.CPU = builder.CPU;
this.RAM = builder.RAM;
this.hardDisk = builder.hardDisk;
this.graphicsCard = builder.graphicsCard;
}
// 内部的静态Builder类
public static class Builder {
private String CPU;
private String RAM;
private String hardDisk;
private String graphicsCard;
public Builder CPU(String CPU) {
this.CPU = CPU;
return this;
}
public Builder RAM(String RAM) {
this.RAM = RAM;
return this;
}
public Builder hardDisk(String hardDisk) {
this.hardDisk = hardDisk;
return this;
}
public Builder graphicsCard(String graphicsCard) {
this.graphicsCard = graphicsCard;
return this;
}
public Computer build() {
return new Computer(this);
}
}
@Override
public String toString() {
return "Computer{" +
"CPU='" + CPU + '\'' +
", RAM='" + RAM + '\'' +
", hardDisk='" + hardDisk + '\'' +
", graphicsCard='" + graphicsCard + '\'' +
'}';
}
}
// Main.java
// 使用
public class Client {
public static void main(String[] args) {
Computer computer = new Computer.Builder()
.CPU("Intel Core i7")
.RAM("16GB")
.hardDisk("1TB SSD")
.graphicsCard("NVIDIA RTX 3080")
.build();
System.out.println(computer);
}
}
golang实现
package main
// Computer 结构体代表要构建的复杂对象
type Computer struct {
CPU string
RAM string
HardDisk string
GraphicsCard string
}
// Builder 接口定义了构建Computer所需的步骤
type Builder interface {
SetCPU(cpu string) Builder
SetRAM(ram string) Builder
SetHardDisk(hd string) Builder
SetGraphicsCard(gc string) Builder
Build() Computer
}
// ComputerBuilder 是实现Builder接口的结构体
type ComputerBuilder struct {
cpu string
ram string
hardDisk string
graphicsCard string
}
func (b *ComputerBuilder) SetCPU(cpu string) Builder {
b.cpu = cpu
return b
}
func (b *ComputerBuilder) SetRAM(ram string) Builder {
b.ram = ram
return b
}
func (b *ComputerBuilder) SetHardDisk(hd string) Builder {
b.hardDisk = hd
return b
}
func (b *ComputerBuilder) SetGraphicsCard(gc string) Builder {
b.graphicsCard = gc
return b
}
func (b *ComputerBuilder) Build() Computer {
return Computer{
CPU: b.cpu,
RAM: b.ram,
HardDisk: b.hardDisk,
GraphicsCard: b.graphicsCard,
}
}
func main() {
builder := ComputerBuilder{}
computer := builder.SetCPU("Intel Core i7").
SetRAM("16GB").
SetHardDisk("1TB SSD").
SetGraphicsCard("NVIDIA RTX 3080").
Build()
fmt.Printf("Computer: %+v\n", computer)
}
5、原型模式(Prototype)
- 目的:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
- 应用场景:当需要创建的对象与现有对象相似,或者当创建对象的成本比直接创建一个类的实例更高时。
- 案例:假设有一个Car类,它有一些昂贵的初始化过程。如果我们需要创建一个与现有Car对象属性完全相同的新对象时,使用原型模式可以避免重新执行昂贵的初始化过程。
- Java实现
// Car.java
public class Car implements Cloneable {
private String make;
private String model;
public Car(String make, String model) {
this.make = make;
this.model = model;
// 假设这里有昂贵的初始化过程
}
public String getMake() {
return make;
}
public String getModel() {
return model;
}
// 实现clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Car{" +
"make='" + make + '\'' +
", model='" + model + '\'' +
'}';
}
}
// Main.java
// 使用
public class Main {
public static void main(String[] args) {
Car car1 = new Car("China", "Xiao mi");
try {
Car car2 = (Car) car1.clone();
System.out.println(car1);
System.out.println(car2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
golang实现
package prototype
// Prototype 接口定义了克隆自身的方法
type Prototype interface {
Clone() Prototype
}
// Car 结构体实现了 Prototype 接口
type Car struct {
Make, Model string
}
// Clone 方法实现了深拷贝
func (c *Car) Clone() Prototype {
return &Car{
Make: c.Make,
Model: c.Model,
}
}
package main
import (
"fmt"
"prototype"
)
func main() {
car1 := &prototype.Car{Make: "China", Model: "Xiao mi"}
// 使用原型模式克隆 Car 实例
car2 := car1.Clone()
fmt.Println(car1) // 输出原始对象
fmt.Println(car2) // 输出克隆对象
}
结构型模式**(Structural Patterns)**
组织不同的类和对象,以形成更大的结构。主要思想是通过组合较小的、简单的部分来构建复杂和功能强大的系统。像用小积木搭建一个大型的模型一样。
1、适配器模式(Adapter)
- 目的:解决接口不兼容的问题,可以将一个类的接口转换成客户端所期望的另一个接口,使得原本用于接口不兼容而无法一起工作的类可以协同工作。
- 应用场景:需要在系统中集成一个新的组件或服务,但其接口与现有系统不兼容时,可以使用适配器模式。
- 案例:一个音频播放器应用,它支持播放MP3格式的文件。现在希望扩展该应用以支持更多格式的音频文件,比如WAV和MP4。但是播放器原生只支持MP3格式。这里可以使用适配器模式来适配其他格式的音频文件。
- 结构图

java 实现
// 音频播放器只支持播放MP3
// MediaPlayer.java
public interface MediaPlayer {
void play(String audioType, String fileName);
}
// AudioPlayer.java
// MP3播放器实现
public class AudioPlayer implements MediaPlayer {
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing MP3 file: " + fileName);
} else {
System.out.println("Invalid file format");
}
}
}
// Client.java
// 客户端代码
public class Client {
public static void main(String[] args) {
MediaPlayer mediaPlayer = new AudioPlayer();
mediaPlayer.play("mp3", "horizon.mp3");
}
}
// 希望支持MAV和MP4格式,待适配的类
// WAVPlayer.java
public class WAVPlayer {
public void playWAV(String fileName) {
System.out.println("Playing WAV file: " + fileName);
}
}
// MP4Player.java
public class MP4Player {
public void playMP4(String fileName) {
System.out.println("Playing MP4 file: " + fileName);
}
}
// 创建适配类
// WAVAdapter.java
public class WAVAdapter implements MediaPlayer {
private WAVPlayer wavPlayer;
public WAVAdapter() {
wavPlayer = new WAVPlayer();
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("wav")) {
wavPlayer.playWAV(fileName);
}
}
}
// MP4Adapter.java
public class MP4Adapter implements MediaPlayer {
private MP4Player mp4Player;
public MP4Adapter() {
mp4Player = new MP4Player();
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("mp4")) {
mp4Player.playMP4(fileName);
}
}
}
// 修改AudioPlayer.java文件,使其适配mav和mp4
// AudioPlayer.java
public class AudioPlayer implements MediaPlayer {
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing MP3 file: " + fileName);
} else if(audioType.equalsIgnoreCase("wav")) {
new WAVAdapter().play(audioType, fileName);
} else if(audioType.equalsIgnoreCase("mp4")) {
new MP4Adapter().play(audioType, fileName);
} else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
// Client.java
public class Client {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("wav", "mind me.wav");
audioPlayer.play("avi", "my movie.avi"); // 不支持的格式
}
}
golang实现
// 定义MediaPlayer接口,声明了播放音频的方法
type MediaPlayer interface {
Play(audioType, fileName string)
}
// 创建WAV和MP4格式的播放器,这些将作为待适配的类
type WAVPlayer struct{}
func (w *WAVPlayer) PlayWAV(fileName string) {
fmt.Println("Playing WAV file:", fileName)
}
type MP4Player struct{}
func (m *MP4Player) PlayMP4(fileName string) {
fmt.Println("Playing MP4 file:", fileName)
}
// 为每种格式创建一个适配器结构体,这些适配器实现了MediaPlayer接口,并内部使用对应格式的播放器来播放音频。
type WAVAdapter struct {
wavPlayer *WAVPlayer
}
func NewWAVAdapter() *WAVAdapter {
return &WAVAdapter{wavPlayer: &WAVPlayer{}}
}
func (wa *WAVAdapter) Play(audioType, fileName string) {
if audioType == "wav" {
wa.wavPlayer.PlayWAV(fileName)
}
}
type MP4Adapter struct {
mp4Player *MP4Player
}
func NewMP4Adapter() *MP4Adapter {
return &MP4Adapter{mp4Player: &MP4Player{}}
}
func (ma *MP4Adapter) Play(audioType, fileName string) {
if audioType == "mp4" {
ma.mp4Player.PlayMP4(fileName)
}
}
// 创建一个AudioPlayer结构体,它使用MediaPlayer接口来播放不同格式的音频文件
type AudioPlayer struct{}
func (a *AudioPlayer) Play(audioType, fileName string) {
switch audioType {
case "mp3":
fmt.Println("Playing MP3 file:", fileName)
case "wav":
adapter := NewWAVAdapter()
adapter.Play(audioType, fileName)
case "mp4":
adapter := NewMP4Adapter()
adapter.Play(audioType, fileName)
default:
fmt.Println("Invalid media. ", audioType, " format not supported")
}
}
// 使用
func main() {
audioPlayer := &AudioPlayer{}
audioPlayer.Play("mp3", "beyond_the_horizon.mp3")
audioPlayer.Play("wav", "mind_me.wav")
audioPlayer.Play("mp4", "alone.mp4")
audioPlayer.Play("avi", "movie.avi") // 不支持的格式
}
2、装饰者模式(Decorator)
- 目的:不改变原始类的基础上,通过添加包装(或装饰)来扩展对象的功能。这种模式创建了一个装饰类,用来包裹原有的类,并在保持原类方法签名完整性的前提下,提供了额外的功能。
- 应用场景:Java中的java.io包中广泛使用了装饰者模式。例如,BufferedReader和BufferedWriter就是装饰了Reader和Writer接口的具体装饰者,提供了缓冲功能,以提高读写的性能。
- 案例:开发一个文本编辑器,基本功能是显示和编辑文本。现希望在不改变现有代码的基础上,动态地添加一些额外的功能,例如拼写检查和语法高亮。
- 结构图:

Java实现
// TextEditor.java
// 抽象组件
public interface TextEditor {
void display();
}
// TextEditor.java
// 具体组件
public class BasicTextEditor implements TextEditor {
@Override
public void display() {
System.out.println("Displaying basic text.");
}
}
// TextEditorDecorator.java
// 装饰者抽象类
public abstract class TextEditorDecorator implements TextEditor {
protected TextEditor decoratedEditor;
public TextEditorDecorator(TextEditor decoratedEditor) {
this.decoratedEditor = decoratedEditor;
}
@Override
public void display() {
decoratedEditor.display();
}
}
// SpellCheckDecorator.java
// 具体装饰者:拼写检查
public class SpellCheckDecorator extends TextEditorDecorator {
public SpellCheckDecorator(TextEditor decoratedEditor) {
super(decoratedEditor);
}
@Override
public void display() {
super.display();
addSpellCheck();
}
private void addSpellCheck() {
System.out.println("Spell checking enabled.");
}
}
// SyntaxHighlightDecorator.java
// 具体装饰者:语法高亮
public class SyntaxHighlightDecorator extends TextEditorDecorator {
public SyntaxHighlightDecorator(TextEditor decoratedEditor) {
super(decoratedEditor);
}
@Override
public void display() {
super.display();
addSyntaxHighlighting();
}
private void addSyntaxHighlighting() {
System.out.println("Syntax highlighting enabled.");
}
}
// Client.java
// 使用装饰者
public class Client {
public static void main(String[] args) {
TextEditor basicEditor = new BasicTextEditor();
TextEditor spellCheckedEditor = new SpellCheckDecorator(basicEditor);
TextEditor highlightedEditor = new SyntaxHighlightDecorator(spellCheckedEditor);
highlightedEditor.display();
}
}
golang实现
package main
import "fmt"
// 抽象组件
type TextEditor interface {
Display()
}
// 具体组件
type BasicTextEditor struct{}
func (b *BasicTextEditor) Display() {
fmt.Println("Displaying basic text.")
}
// 装饰者抽象类
type TextEditorDecorator struct {
decoratedEditor TextEditor
}
func (t *TextEditorDecorator) Display() {
t.decoratedEditor.Display()
}
// 具体装饰者:拼写检查
type SpellCheckDecorator struct {
TextEditorDecorator
}
func (s *SpellCheckDecorator) Display() {
s.TextEditorDecorator.Display()
s.AddSpellCheck()
}
func (s *SpellCheckDecorator) AddSpellCheck() {
fmt.Println("Spell checking enabled.")
}
// 具体装饰者:语法高亮
type SyntaxHighlightDecorator struct {
TextEditorDecorator
}
func (s *SyntaxHighlightDecorator) Display() {
s.TextEditorDecorator.Display()
s.AddSyntaxHighlighting()
}
func (s *SyntaxHighlightDecorator) AddSyntaxHighlighting() {
fmt.Println("Syntax highlighting enabled.")
}
// 使用装饰者
func main() {
basicEditor := &BasicTextEditor{}
spellCheckedEditor := &SpellCheckDecorator{TextEditorDecorator{decoratedEditor: basicEditor}}
highlightedEditor := &SyntaxHighlightDecorator{TextEditorDecorator{decoratedEditor: spellCheckedEditor}}
highlightedEditor.Display()
}
3、代理模式(Proxy)
- 目的:不改变原始类接口的情况下,控制对对象的访问。
- 应用场景: 安全代理用于控制对对象的访问权限。代理对象可以在执行操作前进行身份验证,确保只有经过授权的用户可以访问真实对象。
- 案例:有一个文件操作类,我们希望只有具有特定权限的用户才能执行文件的读写操作。
Java实现
// FileOperation.java
// 接口
public interface FileOperation {
void read();
void write(String data);
}
// RealFileOperation.java
// 真实类
public class RealFileOperation implements FileOperation{
private String fileName;
public RealFileOperation(String fileName) {
this.fileName = fileName;
}
@Override
public void read() {
System.out.println("Reading content from file: " + fileName);
}
@Override
public void write(String data) {
System.out.println("Writing data to file " + fileName + ": " + data);
}
}
// SecureFileProxy.java
// 安全代理
public class SecureFileProxy implements FileOperation{
private RealFileOperation realFile;
private String username;
public SecureFileProxy(String fileName, String username) {
this.realFile = new RealFileOperation(fileName);
this.username = username;
}
public SecureFileProxy() {
}
@Override
public void read() {
if (auth()){
realFile.read();;
} else {
System.out.println("Access denied. Unauthorized user: " + username);
}
}
@Override
public void write(String data) {
if (auth()){
realFile.write(data);
} else {
System.out.println("Access denied. Unauthorized user: " + username);
}
}
private boolean auth(){
// 鉴定用户是否有权限操作
return "admin".equals(username);
}
}
// SecurityProxyMain.java
// 使用
public class SecurityProxyMain {
public static void main(String[] args) {
FileOperation secureFileProxy = new SecureFileProxy("test.log", "admin");
// admin用户可以访问
secureFileProxy.read();
secureFileProxy.write("New content");
FileOperation secureFileProxyForUser = new SecureFileProxy("example.txt", "user");
//普通用户不能访问
secureFileProxyForUser.read();
secureFileProxyForUser.write("Unauthorized attempt");
}
}
golang实现
package main
import "fmt"
// FileOperation 接口
type FileOperation interface {
Read()
Write(data string)
}
// RealFile 实现了 FileOperation 接口的真实文件操作类
type RealFile struct {
FileName string
}
func (rf *RealFile) Read() {
fmt.Println("Reading content from file:", rf.FileName)
}
func (rf *RealFile) Write(data string) {
fmt.Printf("Writing data to file %s: %s\n", rf.FileName, data)
}
// SecureFileProxy 是安全代理,通过组合实现了 FileOperation 接口
type SecureFileProxy struct {
RealFile *RealFile
Username string
Auth bool
}
func NewSecureFileProxy(fileName, username string) *SecureFileProxy {
return &SecureFileProxy{
RealFile: &RealFile{FileName: fileName},
Username: username,
Auth: (username == "admin"), // 仅允许Admin用户访问
}
}
func (sfp *SecureFileProxy) Read() {
if sfp.Auth {
sfp.RealFile.Read()
} else {
fmt.Println("Access denied. Unauthorized user:", sfp.Username)
}
}
func (sfp *SecureFileProxy) Write(data string) {
if sfp.Auth {
sfp.RealFile.Write(data)
} else {
fmt.Println("Access denied. Unauthorized user:", sfp.Username)
}
}
func main() {
// 创建真实文件和安全代理
secureFileProxy := NewSecureFileProxy("example.txt", "Admin")
// Admin用户可以访问
secureFileProxy.Read()
secureFileProxy.Write("New content")
// 普通用户被拒绝访问
secureFileProxyForUser := NewSecureFileProxy("example.txt", "User")
secureFileProxyForUser.Read()
secureFileProxyForUser.Write("Unauthorized attempt")
}
4、桥接模式(Bridge)
- 目的:将抽象部分与其实现部分分离,使它们都可以独立地变化。通过提供一个桥接结构,能够把类的功能层次结构和实现层次结构分离开来,从而在两者间建立一个桥接通道。
- 应用场景:当一个类存在两个独立变化的维度时,可以使用桥接模式分别在两个维度上进行扩展;当需要避免一个类的子类数量的爆炸式增长时。
- 案例:有一个图形绘制的应用程序,其中可以绘制不同类型的图形(如圆形、矩形)并且支持不同的绘图API(如API1、API2)。使用桥接模式,我们可以独立地改变图形的类型和使用的绘图API。
- 结构图:

Java实现
// DrawAPI.java
// 实现化角色
interface DrawAPI {
void drawShape(int radius, int x, int y);
}
// DrawAPI1.java
// 具体实现化角色
class DrawAPI1 implements DrawAPI {
public void drawShape(int radius, int x, int y) {
System.out.println("API1.drawShape at " + x + ", " + y + " with radius " + radius);
}
}
// DrawAPI2.java
class DrawAPI2 implements DrawAPI {
public void drawShape(int radius, int x, int y) {
System.out.println("API2.drawShape at " + x + ", " + y + " with radius " + radius);
}
}
// Shape.java
// 抽象化角色
abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI) {
this.drawAPI = drawAPI;
}
public abstract void draw();
}
// Circle.java
// 修正抽象化角色
class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawShape(radius, x, y);
}
}
// Main.java
// 使用
public class Main {
public static void main(String[] args) {
DrawAPI1 drawAPI1 = new DrawAPI1();
DrawAPI2 drawAPI2 = new DrawAPI2();
Shape circle1 = new Circle(5,2, 10, drawAPI1);
Shape circle2 = new Circle(2,5, 15, drawAPI2);
circle1.draw();
circle2.draw();
}
}
golang实现
package main
import "fmt"
// Implementor 角色 - 绘制API接口
type DrawAPI interface {
drawShape(radius, x, y int)
}
// ConcreteImplementor 角色 - 具体绘制API1
type DrawAPI1 struct{}
func (d *DrawAPI1) drawShape(radius, x, y int) {
fmt.Printf("API1.drawShape at %d, %d with radius %d\n", x, y, radius)
}
// ConcreteImplementor 角色 - 具体绘制API2
type DrawAPI2 struct{}
func (d *DrawAPI2) drawShape(radius, x, y int) {
fmt.Printf("API2.drawShape at %d, %d with radius %d\n", x, y, radius)
}
// Abstraction 角色 - 抽象化接口
type Shape interface {
draw()
}
// RefinedAbstraction 角色 - 修正抽象化,具体的图形类型
type Circle struct {
x, y, radius int
drawAPI DrawAPI
}
func (c *Circle) draw() {
c.drawAPI.drawShape(c.radius, c.x, c.y)
}
// Client 角色
func main() {
// 创建具体绘制API
api1 := &DrawAPI1{}
api2 := &DrawAPI2{}
// 创建具体图形类型
circle1 := &Circle{x: 100, y: 100, radius: 10, drawAPI: api1}
circle2 := &Circle{x: 100, y: 100, radius: 10, drawAPI: api2}
// 使用桥接模式进行绘制
circle1.draw()
circle2.draw()
}
5、组合模式(Composite)
- 目的:组合模式的主要目的是将对象组织成树形结构,使得客户端可以统一地对待单个对象和组合对象。
- 应用场景:表示部分-整体层次结构,例如树形结构、菜单系统等;用户希望统一对待树中的所有对象,而不关心当前处理的是单个对象还是组合对象;当要求体现整体与部分的层次结构时,可以使用组合模式。
- 案例:一个文件系统,文件系统由文件(File)和文件夹(Folder)组成。文件夹可以包含文件和其他文件夹,实现了递归结构。
java实现
// FileSystemComponent.java
// 抽象组件
interface FileSystemComponent {
void display();
}
// File.java
// 文件
class File implements FileSystemComponent {
private String name;
public File(String name) {
this.name = name;
}
public void display() {
System.out.println("File: " + name);
}
}
// Floder.java
// 文件夹
class Folder implements FileSystemComponent {
private String name;
private List<FileSystemComponent> components = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void addComponent(FileSystemComponent component) {
components.add(component);
}
public void removeComponent(FileSystemComponent component) {
components.remove(component);
}
public void display() {
System.out.println("Folder: " + name);
for (FileSystemComponent component : components) {
component.display();
}
}
}
// Main.java
// 使用
public class Main {
public static void main(String[] args) {
File file1 = new File("File1.txt");
File file2 = new File("File2.txt");
Folder folder1 = new Folder("Folder1");
folder1.addComponent(file1);
folder1.addComponent(file2);
File file3 = new File("File3.txt");
Folder mainFolder = new Folder("MainFolder");
mainFolder.addComponent(folder1);
mainFolder.addComponent(file3);
mainFolder.display();
}
}
golang实现
package main
import "fmt"
type FileSystemComponent interface {
display()
}
type File struct {
name string
}
func (f *File) display() {
fmt.Println("File: " + f.name)
}
type Folder struct {
name string
components []FileSystemComponent
}
func (f *Folder) addComponent(component FileSystemComponent) {
f.components = append(f.components, component)
}
func (f *Folder) removeComponent(component FileSystemComponent) {
for i, c := range f.components {
if c == component {
f.components = append(f.components[:i], f.components[i+1:]...)
}
}
}
func (f *Folder) display() {
fmt.Println("Folder: ", f.name)
for _, component := range f.components {
component.display()
}
}
func main() {
file1 := &File{name: "File1.txt"}
file2 := &File{name: "File2.txt"}
file11 := &File{name: "File11.txt"}
folder1 := &Folder{name: "Folder1"}
folder1.addComponent(file1)
folder1.addComponent(file2)
folder1.addComponent(file11)
file3 := &File{name: "File3.txt"}
mainFolder := &Folder{name: "MainFolder"}
mainFolder.addComponent(folder1)
mainFolder.addComponent(file3)
mainFolder.display()
}
6、外观模式(Facade)
- 目的:观模式的主要目的是提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,使得子系统更容易使用。
- 应用场景:当需要为复杂的模块或子系统提供一个简单的接口时;客户程序与多个子系统之间存在很大的依赖性时,可以使用外观来解耦;分层架构中,可以用外观作为每层的入口点,简化层间的通信。
- 案例:考虑一个家庭影院系统,包括灯光、音响、投影仪等组件。每个组件都有自己的操作接口,但为了方便用户,提供一个外观,它提供简单的方法来控制所有这些复杂的设备。
Java实现
// 子系统
// Lights.java
// 灯光系统
public class Lights {
private Integer level;
public Lights() {
}
public Lights(Integer level) {
this.level = level;
}
public void dim() {
System.out.println("把灯光调暗到:" + level + "%");
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
}
// SoundSystem.java
// 声音系统
public class SoundSystem {
private Integer level;
public SoundSystem() {
}
public SoundSystem(Integer level) {
this.level = level;
}
public void setVolume() {
System.out.println("将音量设置为:" + level);
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
}
// Projector.java
// 投影仪系统
public class Projector {
private String movie;
public Projector() {
}
public Projector(String movie) {
this.movie = movie;
}
void turnOn() {
System.out.println("打开投影仪,播放:" + movie);
}
public String getMovie() {
return movie;
}
public void setMovie(String movie) {
this.movie = movie;
}
}
// HomeTheaterFacade.java
// 外观类
public class HomeTheaterFacade {
private Lights lights;
private SoundSystem soundSystem;
private Projector projector;
public HomeTheaterFacade(Lights lights, SoundSystem soundSystem, Projector projector) {
this.lights = lights;
this.soundSystem = soundSystem;
this.projector = projector;
}
void startMovieNight(Integer lightLevel, Integer soundLevel, String movieName) {
lights.setLevel(lightLevel);
lights.dim();
soundSystem.setLevel(soundLevel);
soundSystem.setVolume();
projector.setMovie(movieName);
projector.turnOn();
}
}
// Main.java
// 客户端
public class Main {
public static void main(String[] args) {
Lights lights = new Lights();
SoundSystem soundSystem = new SoundSystem();
Projector projector = new Projector();
HomeTheaterFacade homeTheater = new HomeTheaterFacade(lights, soundSystem, projector);
homeTheater.startMovieNight(80, 7, "<<我不是程序员>>");
}
}
golang实现
package main
import "fmt"
type Lights struct {
level int
}
func (l *Lights) dim() {
fmt.Printf("把灯光调暗到:%d%%\n", l.level)
}
type SoundSystem struct {
level int
}
func (s *SoundSystem) setVolume() {
fmt.Printf("将音量设置为: %d \n", s.level)
}
type Projector struct {
movie string
}
func (p *Projector) turnOn() {
fmt.Printf("打开投影仪,播放: %s \n", p.movie)
}
type HomeTheaterFacaden struct {
lights Lights
soundSystem SoundSystem
projector Projector
}
func (h *HomeTheaterFacaden) startMovieNight(lightLevel, soundLevel int, movie string) {
h.lights.level = lightLevel
h.lights.dim()
h.soundSystem.level = soundLevel
h.soundSystem.setVolume()
h.projector.movie = movie
h.projector.turnOn()
}
func main() {
lights := Lights{}
soundSystem := SoundSystem{}
projector := Projector{}
homeTheater := &HomeTheaterFacaden{
lights: lights,
soundSystem: soundSystem,
projector: projector,
}
homeTheater.startMovieNight(80, 7, "<<我不是程序员>>")
}
7、享元模式(Flyweight)
- 目的:通过共享对象以减少内存或计算开销;适用于大量相似对象存在的场景,以便节省系统资源。
- 应用场景:当一个应用程序使用了大量相似对象,这些对象可以被共享时;当对象的大多数状态都可以变为外部状态,而剩余部分可以提取出来作为共享状态时。
- 案例:一个文本编辑器中字符对象的例子,在一个文本中,有很多相同的字符,例如字母、数字等。为了减少内存占用,可以使用享元模式来共享相同的字符对象,而不是为每个字符都创建一个新的对象。
Java实现
// Char.java
// 享元接口
interface Char {
void print();
}
// ConcreteCharacter.java
// 具体享元类
class ConcreteCharacter implements Char {
private char symbol;
public ConcreteCharacter(char symbol) {
this.symbol = symbol;
}
@Override
public void print() {
System.out.print(symbol);
}
}
// CharacterFactory.java
// 享元工厂
class CharacterFactory {
private Map<Character, ConcreteCharacter> characters = new HashMap<>();
public Char getCharacter(char symbol) {
if (!characters.containsKey(symbol)) {
characters.put(symbol, new ConcreteCharacter(symbol));
}
return characters.get(symbol);
}
}
// 客户端
public class Main {
public static void main(String[] args) {
CharacterFactory characterFactory = new CharacterFactory();
String text = "Hello, World!";
for (char c : text.toCharArray()) {
Char character = characterFactory.getCharacter(c);
character.print();
}
}
}
golang实现
package main
import (
"fmt"
"sync"
)
// Char 享元接口
type Char interface {
Print()
}
// ConcreteCharacter 具体享元类
type ConcreteCharacter struct {
symbol rune
}
func (c *ConcreteCharacter) Print() {
fmt.Printf("%c", c.symbol)
}
// CharacterFactory 享元工厂
type CharacterFactory struct {
characters map[rune]*ConcreteCharacter
mu sync.Mutex
}
func NewCharacterFactory() *CharacterFactory {
return &CharacterFactory{
characters: make(map[rune]*ConcreteCharacter),
}
}
func (cf *CharacterFactory) GetCharacter(symbol rune) Char {
cf.mu.Lock()
defer cf.mu.Unlock()
character, ok := cf.characters[symbol]
if !ok {
character = &ConcreteCharacter{symbol: symbol}
cf.characters[symbol] = character
}
return character
}
// 客户端
func main() {
charFactory := NewCharacterFactory()
text := "Hello, World!"
for _, char := range text {
character := charFactory.GetCharacter(char)
character.Print()
}
fmt.Println()
}
行为型模式**(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)
}
}