软件设计模式(Golang)

76 阅读12分钟

软件设计模式

定义:软件设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结, 目的:是为了可重复代码、让代码更容易被他人理解并且保证代码可靠性

面向对象原则

高内聚,低耦合

image.png

设计模式种类

1. 创建型模式(如何创建对象)

简单工厂模式(违背开闭原则)

通过一个工厂类来创建不同类型的对象,而不需要直接暴露对象的创建逻辑给客户端。简单工厂模式隐藏了对象的创建过程,使得客户端只需要通过工厂类来获取所需的对象实例。

  • 工厂类(Factory):负责创建对象的类。它根据客户端的请求,创建相应的对象并返回给客户端。
  • 抽象产品类(Product):定义了产品的共同接口,它描述了产品具有的属性和方法。
  • 具体产品类(Concrete Product):实现了抽象产品类的接口,是被工厂类创建的对象。
package main

import "fmt"

// 接口:产品
type Product interface {
	Use()
}

// 具体产品类型A
type ProductA struct{}

func (p *ProductA) Use() {
	fmt.Println("Product A is being used")
}

// 具体产品类型B
type ProductB struct{}

func (p *ProductB) Use() {
	fmt.Println("Product B is being used")
}

// 简单工厂
type SimpleFactory struct{}

func (f *SimpleFactory) CreateProduct(productType string) Product {
	switch productType {
	case "A":
		return &ProductA{}
	case "B":
		return &ProductB{}
	default:
		return nil
	}
}

func main() {
	factory := &SimpleFactory{}

	// 创建产品A
	productA := factory.CreateProduct("A")
	productA.Use()

	// 创建产品B
	productB := factory.CreateProduct("B")
	productB.Use()
}
抽象工厂模式

提供了一种方式来创建一系列相关或相互依赖的对象,而无需指定其具体的类

  • 抽象工厂(Abstract Factory):定义了一组创建产品对象的方法,每个方法对应一个具体的产品族。客户端通过调用这些方法来创建所需的产品对象。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体的产品对象。每个具体工厂类对应一个具体的产品族。
  • 抽象产品(Abstract Product):定义了产品对象的接口,描述了产品的共同属性和方法。
  • 具体产品(Concrete Product):实现了抽象产品接口,是由具体工厂创建的对象。
package main

import "fmt"

// 抽象产品A接口
type ProductA interface {
	UseA()
}

// 具体产品A1
type ProductA1 struct{}

func (p *ProductA1) UseA() {
	fmt.Println("Product A1 is being used")
}

// 具体产品A2
type ProductA2 struct{}

func (p *ProductA2) UseA() {
	fmt.Println("Product A2 is being used")
}

// 抽象产品B接口
type ProductB interface {
	UseB()
}

// 具体产品B1
type ProductB1 struct{}

func (p *ProductB1) UseB() {
	fmt.Println("Product B1 is being used")
}

// 具体产品B2
type ProductB2 struct{}

func (p *ProductB2) UseB() {
	fmt.Println("Product B2 is being used")
}

// 抽象工厂接口
type AbstractFactory interface {
	CreateProductA() ProductA
	CreateProductB() ProductB
}

// 具体工厂1
type ConcreteFactory1 struct{}

func (f *ConcreteFactory1) CreateProductA() ProductA {
	return &ProductA1{}
}

func (f *ConcreteFactory1) CreateProductB() ProductB {
	return &ProductB1{}
}

// 具体工厂2
type ConcreteFactory2 struct{}

func (f *ConcreteFactory2) CreateProductA() ProductA {
	return &ProductA2{}
}

func (f *ConcreteFactory2) CreateProductB() ProductB {
	return &ProductB2{}
}

func main() {
	// 使用具体工厂1创建产品A和产品B
	factory1 := &ConcreteFactory1{}
	productA1 := factory1.CreateProductA()
	productB1 := factory1.CreateProductB()
	productA1.UseA()
	productB1.UseB()

	// 使用具体工厂2创建产品A和产品B
	factory2 := &ConcreteFactory2{}
	productA2 := factory2.CreateProductA()
	productB2 := factory2.CreateProductB()
	productA2.UseA()
	productB2.UseB()
}
单例模式

确保一个类只有一个实例,并提供一个全局访问点来访问该实例。

package main

import (
	"fmt"
	"sync"
)

// 单例对象
type Singleton struct {
	data string
}

// 单例对象的实例
var instance *Singleton

// 用于保证线程安全的锁和一次性执行
var once sync.Once

// 获取单例对象的方法
func GetInstance() *Singleton {
	once.Do(func() {
		instance = &Singleton{data: "Hello, Singleton!"}
	})
	return instance
}

func main() {
	// 获取单例对象
	singleton := GetInstance()

	// 使用单例对象
	fmt.Println(singleton.data)
}

2. 结构型模式(如何实现类或对象的组合)

代理模式

允许通过一个代理对象来控制对真实对象的访问

  • 抽象主题(Abstract Subject):定义了真实主题和代理主题的共同接口,这样代理类就可以在任何使用真实主题的地方替代它。
  • 真实主题(Real Subject):实现了抽象主题接口,是代理所代表的真实对象,是客户端所关心的对象。
  • 代理主题(Proxy Subject):实现了抽象主题接口,包含一个指向真实主题的引用,可以控制对真实主题的访问,并在访问前后执行额外的操作。
package main

import "fmt"

// 接口:主题
type Subject interface {
	Request()
}

// 具体主题
type ConcreteSubject struct{}

func (s *ConcreteSubject) Request() {
	fmt.Println("ConcreteSubject handles the request")
}

// 代理
type Proxy struct {
	subject Subject
}

func (p *Proxy) Request() {
	// 在调用具体主题前后可以添加额外的逻辑
	fmt.Println("Proxy handles the request before")
	p.subject.Request()
	fmt.Println("Proxy handles the request after")
}

func main() {
	// 创建具体主题
	subject := &ConcreteSubject{}

	// 创建代理,并将具体主题作为参数传入
	proxy := &Proxy{
		subject: subject,
	}

	// 通过代理调用请求
	proxy.Request()
}
装饰器模式

不改变原有对象接口的情况下,动态地扩展对象的功能

  • 抽象构件(Component):定义了原始对象和装饰器对象的共同接口,可以是抽象类或接口。
  • 具体构件(Concrete Component):实现了抽象构件接口,是需要被装饰的原始对象。
  • 抽象装饰器(Decorator):继承了抽象构件接口,并持有一个抽象构件的引用,用于包装原始对象。
  • 具体装饰器(Concrete Decorator):继承了抽象装饰器,并实现了额外的功能。它可以在调用原始对象的方法之前或之后执行一些操作,以扩展原始对象的功能。
package main

import "fmt"

// 接口:组件
type Component interface {
	Operation()
}

// 具体组件
type ConcreteComponent struct{}

func (c *ConcreteComponent) Operation() {
	fmt.Println("ConcreteComponent operation")
}

// 装饰器
type Decorator struct {
	component Component
}

func (d *Decorator) Operation() {
	// 在调用具体组件前后可以添加额外的逻辑
	fmt.Println("Decorator operation before")
	d.component.Operation()
	fmt.Println("Decorator operation after")
}

func main() {
	// 创建具体组件
	component := &ConcreteComponent{}

	// 创建装饰器,并将具体组件作为参数传入
	decorator := &Decorator{
		component: component,
	}

	// 通过装饰器调用操作
	decorator.Operation()
}
适配器模式

将一个类的接口转换成客户端所期望的另一个接口

  • 目标接口(Target Interface):定义了客户端期望的接口,客户端通过这个接口与适配器进行交互。
  • 适配器(Adapter):实现了目标接口,同时持有一个适配者对象的引用。适配器将客户端的请求转发给适配者对象来完成实际的操作。
  • 适配者(Adaptee):原本已经存在的类,包含了客户端所需要的功能,但与目标接口不兼容。
package main

import "fmt"

// 目标接口
type Target interface {
	Request()
}

// 源接口
type Adaptee interface {
	SpecificRequest()
}

// 源类型
type ConcreteAdaptee struct{}

func (a *ConcreteAdaptee) SpecificRequest() {
	fmt.Println("Specific request")
}

// 适配器
type Adapter struct {
	adaptee Adaptee
}

func (a *Adapter) Request() {
	// 调用适配者的方法来实现目标接口的方法
	a.adaptee.SpecificRequest()
}

func main() {
	// 创建适配者
	adaptee := &ConcreteAdaptee{}

	// 创建适配器,并将适配者作为参数传入
	adapter := &Adapter{
		adaptee: adaptee,
	}

	// 通过适配器调用目标接口方法
	adapter.Request()
}
外观模式

提供了一个统一的接口,用于访问子系统中一组接口的功能

  • 外观(Facade):提供了一个简化的接口,用于访问子系统中一组接口的功能。它知道哪些子系统类负责处理客户端的请求,将请求委派给相应的子系统对象进行处理。
  • 子系统类(Subsystem Classes):实现了子系统的功能,处理外观对象指派的任务。子系统类可以是单个类,也可以是一组相关的类。
package main

import "fmt"

// 子系统A
type SubsystemA struct{}

func (s *SubsystemA) OperationA() {
	fmt.Println("Subsystem A operation")
}

// 子系统B
type SubsystemB struct{}

func (s *SubsystemB) OperationB() {
	fmt.Println("Subsystem B operation")
}

// 外观
type Facade struct {
	subsystemA *SubsystemA
	subsystemB *SubsystemB
}

func NewFacade() *Facade {
	return &Facade{
		subsystemA: &SubsystemA{},
		subsystemB: &SubsystemB{},
	}
}

func (f *Facade) Operation() {
	// 调用子系统的方法
	f.subsystemA.OperationA()
	f.subsystemB.OperationB()
}

func main() {
	// 创建外观
	facade := NewFacade()

	// 通过外观调用操作
	facade.Operation()
}
组合模式

将对象组合成树状结构,以表示部分-整体的层次结构

  • 抽象构件(Component):定义了组合中的对象共有的接口,可以是抽象类或接口。它声明了访问和管理子对象的方法,以及一些默认的行为。
  • 叶子构件(Leaf):表示树中的叶子节点,没有子节点。实现了抽象构件的接口。
  • 组合构件(Composite):表示树中的分支节点,具有子节点。实现了抽象构件的接口,并提供了管理子节点的方法。
package main

import "fmt"

// 抽象组件接口
type Component interface {
	Operation()
}

// 叶子节点
type Leaf struct {
	name string
}

func (l *Leaf) Operation() {
	fmt.Println("Leaf", l.name, "operation")
}

// 组合节点
type Composite struct {
	name       string
	components []Component
}

func (c *Composite) Operation() {
	fmt.Println("Composite", c.name, "operation")

	// 遍历并调用子组件的操作方法
	for _, component := range c.components {
		component.Operation()
	}
}

func (c *Composite) Add(component Component) {
	c.components = append(c.components, component)
}

func (c *Composite) Remove(component Component) {
	for i, comp := range c.components {
		if comp == component {
			c.components = append(c.components[:i], c.components[i+1:]...)
			break
		}
	}
}

func main() {
	// 创建树状结构
	root := &Composite{name: "root"}

	leaf1 := &Leaf{name: "leaf1"}
	leaf2 := &Leaf{name: "leaf2"}

	subComposite := &Composite{name: "subComposite"}
	subLeaf := &Leaf{name: "subLeaf"}

	root.Add(leaf1)
	root.Add(leaf2)
	root.Add(subComposite)
	subComposite.Add(subLeaf)

	// 调用根节点的操作方法,会递归执行子节点的操作方法
	root.Operation()
}
桥接模式

将抽象部分和实现部分分离,使它们可以独立地变化和扩展

  • 抽象部分(Abstraction):定义了抽象部分的接口,并维护一个指向实现部分的引用。它通常包含抽象部分的业务逻辑。
  • 实现部分(Implementation):定义了实现部分的接口,提供了实现部分的具体实现。
  • 具体抽象部分(Concrete Abstraction):继承自抽象部分,实现了抽象部分的接口,并调用实现部分的具体实现。
  • 具体实现部分(Concrete Implementation):继承自实现部分,实现了实现部分的接口。
package main

import "fmt"

// 实现者接口
type Implementor interface {
	OperationImpl()
}

// 具体实现者A
type ConcreteImplementorA struct{}

func (c *ConcreteImplementorA) OperationImpl() {
	fmt.Println("Concrete Implementor A operation")
}

// 具体实现者B
type ConcreteImplementorB struct{}

func (c *ConcreteImplementorB) OperationImpl() {
	fmt.Println("Concrete Implementor B operation")
}

// 抽象类
type Abstraction struct {
	implementor Implementor
}

func (a *Abstraction) SetImplementor(implementor Implementor) {
	a.implementor = implementor
}

func (a *Abstraction) Operation() {
	if a.implementor != nil {
		a.implementor.OperationImpl()
	}
}

// 客户端代码
func main() {
	// 创建抽象类对象
	abstraction := &Abstraction{}

	// 创建具体实现者对象
	implementorA := &ConcreteImplementorA{}
	implementorB := &ConcreteImplementorB{}

	// 将具体实现者A关联到抽象类对象
	abstraction.SetImplementor(implementorA)
	// 调用抽象类的操作方法,实际上执行的是具体实现者A的方法
	abstraction.Operation()

	// 将具体实现者B关联到抽象类对象
	abstraction.SetImplementor(implementorB)
	// 调用抽象类的操作方法,实际上执行的是具体实现者B的方法
	abstraction.Operation()
}

3. 行为型模式(类或对象怎样交互以及怎样分配职责)

命令模式

将请求封装成一个对象,从而使得可以用不同的请求对客户端进行参数化

  • 命令(Command):定义了执行操作的接口,通常包含一个执行方法。
  • 具体命令(ConcreteCommand):实现了命令接口,持有接收者对象,并在执行方法中调用接收者的相应操作。
  • 接收者(Receiver):负责执行具体的操作。
  • 请求者/调用者(Invoker):持有命令对象,并在需要执行操作时调用命令对象的执行方法。
  • 客户端(Client):创建命令对象、接收者对象和请求者对象,并进行它们之间的组装。
package main

import "fmt"

// 命令接口
type Command interface {
	Execute()
}

// 具体命令A
type ConcreteCommandA struct {
	receiver *Receiver
}

func (c *ConcreteCommandA) Execute() {
	c.receiver.ActionA()
}

// 具体命令B
type ConcreteCommandB struct {
	receiver *Receiver
}

func (c *ConcreteCommandB) Execute() {
	c.receiver.ActionB()
}

// 接收者
type Receiver struct{}

func (r *Receiver) ActionA() {
	fmt.Println("Receiver: Action A")
}

func (r *Receiver) ActionB() {
	fmt.Println("Receiver: Action B")
}

// 请求者/调用者
type Invoker struct {
	command Command
}

func (i *Invoker) SetCommand(command Command) {
	i.command = command
}

func (i *Invoker) ExecuteCommand() {
	i.command.Execute()
}

// 客户端代码
func main() {
	// 创建接收者对象
	receiver := &Receiver{}

	// 创建具体命令A和B对象,并关联接收者
	commandA := &ConcreteCommandA{receiver: receiver}
	commandB := &ConcreteCommandB{receiver: receiver}

	// 创建请求者对象,并设置命令A
	invoker := &Invoker{}
	invoker.SetCommand(commandA)

	// 执行命令A
	invoker.ExecuteCommand()

	// 设置命令B
	invoker.SetCommand(commandB)

	// 执行命令B
	invoker.ExecuteCommand()
}
策略模式

定义了一系列算法,并将每个算法封装在独立的类中,使得它们可以互相替换

  • 策略接口(Strategy):定义了算法的公共接口,所有具体策略类都必须实现该接口。
  • 具体策略(ConcreteStrategy):实现了策略接口,提供具体的算法实现。
  • 环境类(Context):持有一个策略对象,并在需要执行算法时调用策略对象的方法。
package main

import "fmt"

// 策略接口
type Strategy interface {
	Execute()
}

// 具体策略A
type ConcreteStrategyA struct{}

func (s *ConcreteStrategyA) Execute() {
	fmt.Println("Executing strategy A")
}

// 具体策略B
type ConcreteStrategyB struct{}

func (s *ConcreteStrategyB) Execute() {
	fmt.Println("Executing strategy B")
}

// 环境类
type Context struct {
	strategy Strategy
}

func (c *Context) SetStrategy(strategy Strategy) {
	c.strategy = strategy
}

func (c *Context) ExecuteStrategy() {
	if c.strategy != nil {
		c.strategy.Execute()
	}
}

// 客户端代码
func main() {
	// 创建具体策略A和策略B对象
	strategyA := &ConcreteStrategyA{}
	strategyB := &ConcreteStrategyB{}

	// 创建环境对象
	context := &Context{}

	// 设置策略A,并执行策略
	context.SetStrategy(strategyA)
	context.ExecuteStrategy()

	// 设置策略B,并执行策略
	context.SetStrategy(strategyB)
	context.ExecuteStrategy()
}
观察者模式

定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,它的所有依赖对象都会收到通知并自动更新

  • 主题(Subject):也称为可观察者,它维护着一组观察者对象,提供注册、取消注册和通知观察者的方法。
  • 观察者(Observer):定义了接收主题通知的接口,通常包含一个更新方法,用于在主题状态改变时更新自身。
  • 具体主题(ConcreteSubject):实现了主题接口,维护着观察者对象的列表,并在状态改变时通知观察者。
  • 具体观察者(ConcreteObserver):实现了观察者接口,通过注册到具体主题上,接收到主题通知时进行更新。
package main

import "fmt"

// 观察者接口
type Observer interface {
	Update()
}

// 主题接口
type Subject interface {
	Register(observer Observer)
	Unregister(observer Observer)
	Notify()
}

// 具体观察者A
type ConcreteObserverA struct{}

func (o *ConcreteObserverA) Update() {
	fmt.Println("ConcreteObserverA: Received update")
}

// 具体观察者B
type ConcreteObserverB struct{}

func (o *ConcreteObserverB) Update() {
	fmt.Println("ConcreteObserverB: Received update")
}

// 具体主题
type ConcreteSubject struct {
	observers []Observer
}

func (s *ConcreteSubject) Register(observer Observer) {
	s.observers = append(s.observers, observer)
}

func (s *ConcreteSubject) Unregister(observer Observer) {
	for i, o := range s.observers {
		if o == observer {
			s.observers = append(s.observers[:i], s.observers[i+1:]...)
			break
		}
	}
}

func (s *ConcreteSubject) Notify() {
	for _, observer := range s.observers {
		observer.Update()
	}
}

// 客户端代码
func main() {
	// 创建具体观察者A和B对象
	observerA := &ConcreteObserverA{}
	observerB := &ConcreteObserverB{}

	// 创建具体主题对象
	subject := &ConcreteSubject{}

	// 注册观察者A和B到主题
	subject.Register(observerA)
	subject.Register(observerB)

	// 发送通知给观察者
	subject.Notify()

	// 取消观察者B的注册
	subject.Unregister(observerB)

	// 再次发送通知给观察者
	subject.Notify()
}