设计模式 golang 实现

仅为学习设计模式的记录

创建型模式

抽象工厂

抽象工厂模式 Abstract factory,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

UML Diagram

实现

为 CPU 创建一个接口,然后创建实现接口的实体类。

package abstractfactory

import "fmt"

// cpu 的接口
type CPUApi interface {
	Calculate() string // CPU 具有运算的功能
}

// IntelCPU

type IntelCPU struct {
	pins int // CPU 的针脚数目
}

// SetPoins 设置针脚数目
func (i *IntelCPU) SetPoins(p int) {
	i.pins = p
}

// Calculate 运算
// @return 返回计算结果
func (i *IntelCPU) Calculate() string {
	return fmt.Sprintf("now in Intel CPU,pins=%v", i.pins)
}

// AMDCPU

type AMDCPU struct {
	pins int // CPU 的针脚数目
}

// SetPoins 设置针脚数目
func (i *AMDCPU) SetPoins(p int) {
	i.pins = p
}

// Calculate 运算
// @return 返回计算结果
func (i *AMDCPU) Calculate() string {
	return fmt.Sprintf("now in AMD CPU,pins=%v", i.pins)
}

为主板创建一个接口,然后创建实现接口的实体类。

package abstractfactory

import "fmt"

// 主板的接口
type MainboardApi interface {
	InstallCPU() string // 主板具有安装 CPU 的功能
}

// IntelMainboard 主板
type IntelMainboard struct {
	cpuHoles int // CPU 插槽的孔数
}

// SetCpuHoles 设置 CPU 插槽的孔数
func (i *IntelMainboard) SetCpuHoles(p int) {
	i.cpuHoles = p
}

// InstallCPU 安装 CPU
// @return 返回安装结果
func (i *IntelMainboard) InstallCPU() string {
	return fmt.Sprintf("now in IntelMainboard,cpuHoles=%v", i.cpuHoles)
}

//  AMDMainboard AMD 主板
type AMDMainboard struct {
	cpuHoles int // CPU 插槽的孔数
}

// SetCpuHoles 设置 CPU 插槽的孔数
func (i *AMDMainboard) SetCpuHoles(p int) {
	i.cpuHoles = p
}

// InstallCPU 安装 CPU
// @return 返回安装结果
func (i *AMDMainboard) InstallCPU() string {
	return fmt.Sprintf("now in AMDMainboard,cpuHoles=%v", i.cpuHoles)
}

定义抽象工厂接口,AMDFactoryIntelFactory 两种不同的装机工厂

package abstractfactory

type AbstractFactoryAPI interface {
	CreateCUPApi() CPUApi             // 创建 cup 对象, @return cpu 对象
	CreateMainboardApi() MainboardApi // 创建 Mainboard 对象, @return Mainboard 对象
}

// AMD 装机工厂,Intel 的 CPU + 主板
// 这里创建 CPU 和主板对象的时候,是对应的,能匹配上的
type AMDFactory struct{}

func NewAMDFactory() *AMDFactory {
	return &AMDFactory{}
}

func (*AMDFactory) CreateCUPApi() CPUApi {
	return &AMDCPU{1156}
}

func (*AMDFactory) CreateMainboardApi() MainboardApi {
	return &AMDMainboard{1156}
}

// Intel 装机工厂,AMD 的 CPU + 主板
// 这里创建 CPU 和主板对象的时候,是对应的,能匹配上的
type IntelFactory struct{}

func NewIntelFactory() *IntelFactory {
	return &IntelFactory{}
}

func (IntelFactory) CreateCUPApi() CPUApi {
	return &IntelCPU{939}
}

func (IntelFactory) CreateMainboardApi() MainboardApi {
	return &IntelMainboard{939}
}

定义使用抽象工厂的客户端,即装机工程师类

package abstractfactory

import (
	"fmt"
)

// ComputerEngineer 工程师类

type ComputerEngineer struct {
	cpu       CPUApi
	mainboard MainboardApi
}

func NewComputerEngineer() *ComputerEngineer {
	return &ComputerEngineer{}
}

// 装机过程
// @param f 客户选择的装机方案
func (c *ComputerEngineer) MakeComputer(f AbstractFactoryAPI) string {
	return c.prepareHardwares(f)
}

// 准备装机所需要的配件
// @param f 客户选择的装机方案
func (c *ComputerEngineer) prepareHardwares(f AbstractFactoryAPI) string {
	c.cpu = f.CreateCUPApi()
	c.mainboard = f.CreateMainboardApi()
	return fmt.Sprintf("%s;%s", c.cpu.Calculate(), c.mainboard.InstallCPU())
}

测试代码

package abstractfactory

import (
	"testing"
)

// 测试抽象工厂
func TestAbstractfactory(t *testing.T) {

	// 装机工程师
	computerEngineer := NewComputerEngineer()
	f1 := NewAMDFactory()
	f2 := NewIntelFactory()

	s := computerEngineer.MakeComputer(f1)
	if s != "now in AMD CPU,pins=1156;now in AMDMainboard,cpuHoles=1156" {
		t.Fatal("TestAbstractfactory test fail")
	}

	s = computerEngineer.MakeComputer(f2)
	if s != "now in Intel CPU,pins=939;now in IntelMainboard,cpuHoles=939" {
		t.Fatal("TestAbstractfactory test fail")
	}
}

简单工厂

基本概念

将对象创建的逻辑封装起来,为使用者提供一个简单易用的对象创建接口

目的:定义一个创建对象的接口,通过使用一个共同的接口来指向新创建的对象 应用场景:

限制和约束因素:

尽量遵循单一职责,一个类只提供一种功能。

UML Diagram

案例

考虑有不同的 Shape 对象,分别是 Rectangle, Square, Circle

package simpleFactory

type Shape interface {
	draw() string
}

type Rectangle struct{}

func (*Rectangle) draw() string {
	return "Inside Rectangle::draw() method."
}

type Square struct{}

func (*Square) draw() string {
	return "Inside Square::draw() method."
}

type Circle struct{}

func (*Circle) draw() string {
	return "Inside Circle::draw() method."
}

Share 提供一个工厂对象:

package simpleFactory

type Factory struct{}

func (f *Factory) Create(shape_type string) Shape {
	if shape_type == "CIRCLE" {
		return &Circle{}
	} else if shape_type == "RECTANGLE" {
		return &Rectangle{}
	} else if shape_type == "SQUARE" {
		return &Square{}
	}
	return nil
}

测试代码如下:

package simpleFactory

import "testing"

func TestGetShape(t *testing.T) {
	f := &Factory{}
	s := f.Create("CIRCLE")
	if s.draw() != "Inside Circle::draw() method." {
		t.Fatal("Circle::draw() test fail")
	}

	s = f.Create("RECTANGLE")
	if s.draw() != "Inside Rectangle::draw() method." {
		t.Fatal("Rectangle::draw() test fail")
	}

	s = f.Create("SQUARE")
	if s.draw() != "Inside Square::draw() method." {
		t.Fatal("Square::draw() test fail")
	}
}

单例模式

目的:保证一个实例 应用场景:

限制和约束因素:

实现

golang 闭包版单例模式:

func GetLoggerSingle() func() *zap.Logger {
	var logger *zap.Logger
	return func() *zap.Logger {
		if logger == nil {
			logger = zap.NewExample()
		}
		return logger
	}
}

var GetLogger = GetLoggerSingle()

golang 线程安全单例模式:

var once sync.Once
var logger *zap.Logger

func GetLogger() *zap.Logger {
	once.Do(func() {
		logger = zap.NewExample()
	})
	return logger
}

建造者模式

建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

UML Diagram

实现

Product:定义产品的结构。 (在我们的例子中是 CellPhone)。

BuildProcess:它是定义构建产品所要采取的步骤的接口。 它没有定义任何逻辑,只是定义了流程的蓝图。 它是代码的一部分,而不是如何去做。

具体实现:这是如何做部分代码。 所有产品都实施构建过程以满足他们的需求。 考虑到所讨论的手机示例,Iphone 将具有与 Xiaomi 不同的具体实现。

Director:Director 是使用构建器界面构建产品的客户。 它的职责是执行构建过程中定义的步骤。

package builder

import (
	"fmt"
)

type CellPhone struct {
	Name         string
	Camera       bool
	DualSim      bool
	Torch        bool
	ColorDisplay bool
}

func (c *CellPhone) printProduct() {
	fmt.Printf("%s has camera? %v\n", c.Name, c.Camera)
	fmt.Printf("%s has Dual Sim? %v\n", c.Name, c.DualSim)
	fmt.Printf("%s has Torch? %v\n", c.Name, c.Torch)
	fmt.Printf("%s has Color Display? %v\n", c.Name, c.ColorDisplay)
}

// 构建过程
type BuildProcess interface {
	SetName() BuildProcess
	SetCamera() BuildProcess
	SetDualSim() BuildProcess
	SetTorch() BuildProcess
	SetColorDisplay() BuildProcess
	GetCellPhone() CellPhone
}

type Iphone struct {
	Phone CellPhone
}

func (n *Iphone) SetName() BuildProcess {
	n.Phone.Name = "Iphone"
	return n
}

func (n *Iphone) SetCamera() BuildProcess {
	n.Phone.Camera = false
	return n
}

func (n *Iphone) SetDualSim() BuildProcess {
	n.Phone.DualSim = false
	return n
}

func (n *Iphone) SetTorch() BuildProcess {
	n.Phone.Torch = true
	return n
}

func (n *Iphone) SetColorDisplay() BuildProcess {
	n.Phone.ColorDisplay = false
	return n
}

func (n *Iphone) GetCellPhone() CellPhone {
	return n.Phone
}

type Xiaomi struct {
	Phone CellPhone
}

func (n *Xiaomi) SetName() BuildProcess {
	n.Phone.Name = "Xiaomi"
	return n
}

func (s *Xiaomi) SetCamera() BuildProcess {
	s.Phone.Camera = true
	return s
}

func (s *Xiaomi) SetDualSim() BuildProcess {
	s.Phone.DualSim = true
	return s
}

func (s *Xiaomi) SetTorch() BuildProcess {
	s.Phone.Torch = false
	return s
}

func (s *Xiaomi) SetColorDisplay() BuildProcess {
	s.Phone.ColorDisplay = true
	return s
}

func (s *Xiaomi) GetCellPhone() CellPhone {
	return s.Phone
}

type Director struct {
	builder BuildProcess
}

func (d *Director) SetBuilder(b BuildProcess) {
	d.builder = b
}

func (d *Director) Construct() CellPhone {
	d.builder.SetName().SetCamera().SetDualSim().SetTorch().SetColorDisplay()
	return d.builder.GetCellPhone()
}

测试代码:

package builder

import (
	"fmt"
	"testing"
)

//TestAdapter
func TestAdapter(t *testing.T) {
	diro := Director{}
	iphone := &Iphone{}
	diro.SetBuilder(iphone)
	phone := diro.Construct()
	phone.printProduct()
	fmt.Println("--------")
	xiaomi := &Xiaomi{}
	diro.SetBuilder(xiaomi)
	phone = diro.Construct()
	phone.printProduct()
}

结构型模式

适配器模式

将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

UML Diagram

实现

考虑有不同的 Shape 对象,分别是 Point, Line, Square

package adapter

import "fmt"

type Shape interface {
	display()
	fill()
	undisplay()
}

type Point struct{}

func (s *Point) display() {
	fmt.Println("Inside Point::display() method.")
}

func (s *Point) fill() {
	fmt.Println("Inside Point::display() method.")
}

func (s *Point) undisplay() {
	fmt.Println("Inside Point::undisplay() method.")
}

type Line struct{}

func (s *Line) display() {
	fmt.Println("Inside Line::display() method.")
}

func (s *Line) fill() {
	fmt.Println("Inside Line::display() method.")
}

func (s *Line) undisplay() {
	fmt.Println("Inside Line::undisplay() method.")
}

type Square struct{}

func (s *Square) display() {
	fmt.Println("Inside Line::display() method.")
}

func (s *Square) fill() {
	fmt.Println("Inside Line::display() method.")
}

func (s *Square) undisplay() {
	fmt.Println("Inside Line::undisplay() method.")
}

type XXCircle struct{}

func (s *XXCircle) displayIt() {
	fmt.Println("Inside XXCircle::display() method.")
}

func (s *XXCircle) fillIt() {
	fmt.Println("Inside XXCircle::display() method.")
}

func (s *XXCircle) undisplayIt() {
	fmt.Println("Inside XXCircle::undisplay() method.")
}

现在我们需要实现一个圆(一种新的 Shape),但是发现已经被别人写好了,糟糕的是它的命名方法和 Shape 定义的不一致


type XXCircle struct{}

func (s *XXCircle) displayIt() {
	fmt.Println("Inside XXCircle::display() method.")
}

func (s *XXCircle) fillIt() {
	fmt.Println("Inside XXCircle::display() method.")
}

func (s *XXCircle) undisplayIt() {
	fmt.Println("Inside XXCircle::undisplay() method.")
}

我们无法改变它,只能去想办法适配它

package adapter

type Circle struct {
	circle *XXCircle
}

func NewCircle() *Circle {
	return &Circle{&XXCircle{}}
}

func (s *Circle) display() {
	s.circle.displayIt()
}

func (s *Circle) fill() {
	s.circle.fillIt()
}

func (s *Circle) undisplay() {
	s.circle.undisplayIt()
}

测试代码

package adapter

import "testing"

//TestAdapter
func TestAdapter(t *testing.T) {
	circle := NewCircle()
	circle.display()
	circle.fill()
	circle.undisplay()
}

外观模式

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

UML Diagram

实现

考虑有不同的 Shape 对象,分别是 Rectangle, Square, Circle

package facade

type Shape interface {
	draw() string
}

type Rectangle struct{}

func (*Rectangle) draw() string {
	return "Rectangle::draw()"
}

type Square struct{}

func (*Square) draw() string {
	return "Square::draw()"
}

type Circle struct{}

func (*Circle) draw() string {
	return "Circle::draw()"
}

定义一个外观类 ShapeMaker,隔离内部复杂的子系统,简化与客户端的接口

package facade

type ShapeMaker struct {
	circle    Shape
	rectangle Shape
	square    Shape
}

func NewShapeMaker() *ShapeMaker {
	s := &ShapeMaker{}
	s.circle = &Circle{}
	s.rectangle = &Rectangle{}
	s.square = &Square{}
	return s
}

func (s *ShapeMaker) exec() string {
	result := ""
	result += s.circle.draw()
	result += s.rectangle.draw()
	result += s.square.draw()
	return result
}

测试代码:

package facade

import (
	"testing"
)

func TestNewShapeMaker(t *testing.T) {
	s := NewShapeMaker()
	ret := s.exec()
	if ret != "Circle::draw()Rectangle::draw()Square::draw()" {
		t.Fatal("NewShapeMaker test fail")
	}
}

代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

UML Diagram

实现

package main

import "fmt"

type server interface {
	handleRequest(string, string) (int, string)
}

type nginx struct {
	application       *application
	maxAllowedRequest int
	rateLimiter       map[string]int
}

func newNginxServer() *nginx {
	return &nginx{
		application:       &application{},
		maxAllowedRequest: 2,
		rateLimiter:       make(map[string]int),
	}
}

func (n *nginx) handleRequest(url, method string) (int, string) {
	allowed := n.checkRateLimiting(url)
	if !allowed {
		return 403, "Not Allowed"
	}
	return n.application.handleRequest(url, method)
}

func (n *nginx) checkRateLimiting(url string) bool {
	if n.rateLimiter[url] == 0 {
		n.rateLimiter[url] = 1
	}
	if n.rateLimiter[url] > n.maxAllowedRequest {
		return false
	}
	n.rateLimiter[url] += 1
	return true
}

type application struct {
}

func (n *application) handleRequest(url, method string) (int, string) {
	if url == "/app/status" && method == "GET" {
		return 200, "Ok"
	}
	if url == "/create/user" && method == "POST" {
		return 201, "User Created"
	}
	return 404, "Not Ok"
}

func main() {
	nginxServer := newNginxServer()
	appStatusURL := "/app/status"
	createuserURL := "/create/user"
	httpCode, body := nginxServer.handleRequest(appStatusURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(createuserURL, "POST")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
	httpCode, body = nginxServer.handleRequest(createuserURL, "GET")
	fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
}

装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象动态的添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

UML Diagram

实现

假设我们在写一个飞机战斗游戏,随着经验值增加,我们需要给飞机升级为更厉害的飞机,一开始发射普通子弹,第二级发射极光武器,第三季可以发射导弹

代码中省略了 AttackDecorator 抽象类

package decoratorpackage decorator

import "fmt"

type Attack interface {
	fire()
}

type Plan struct {
	Attack
}

func (p *Plan) fire() {
	fmt.Println("发射普通子弹")
}

// 导弹
type MissileDecorator struct {
	Attack
	plan *Plan
}

func (p *MissileDecorator) fire() {
	p.plan.fire()
	fmt.Println("发射导弹")
}

// 激光
type LaserDecorator struct {
	Attack
	plan *Plan
}

func (p *LaserDecorator) fire() {
	p.plan.fire()
	fmt.Println("发射起光")
}

测试代码

package decorator

import (
	"fmt"
	"testing"
)

func TestDecorator(t *testing.T) {
	plan := &Plan{}
	fmt.Println("Plan fire:")
	plan.fire()

	missile := &MissileDecorator{
		plan: plan,
	}

	fmt.Println("MissileDecorator fire:")
	missile.fire()

	laser := &LaserDecorator{
		plan: plan,
	}

	fmt.Println("LaserDecorator fire:")
	laser.fire()
}

组合模式

Composition 模式将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

应用场景:图形界面、树形菜单、文件夹和文件管理

UML

实现

package component

import "fmt"

type component interface {
	search(string)
}

type folder struct {
	components []component
	name       string
}

func (f *folder) search(keyword string) {
	fmt.Printf("Serching recursively for keyword %s in folder %s\n", keyword, f.name)
	for _, composite := range f.components {
		composite.search(keyword)
	}
}

func (f *folder) add(c component) {
	f.components = append(f.components, c)
}

type file struct {
	name string
}

func (f *file) search(keyword string) {
	fmt.Printf("Searching for keyword %s in file %s\n", keyword, f.name)
}

func (f *file) getName() string {
	return f.name
}

测试代码:

package component

import (
	"testing"
)

func TestComponent(t *testing.T) {
	file1 := &file{name: "File1"}
	file2 := &file{name: "File2"}
	file3 := &file{name: "File3"}
	folder1 := &folder{
		name: "Folder1",
	}
	folder1.add(file1)

	folder2 := &folder{
		name: "Folder2",
	}
	folder2.add(file2)
	folder2.add(file3)
	folder2.add(folder1)
	folder2.search("rose")
}

行为型模式

策略模式

UML Diagram

实现

假设我们要实现简单的计算有 加、减、乘三种方法,我们可以使用策略模式来替换不同的算法

package strategy

type Strategy interface {
	doOperation(int, int) int
}

type OperationAdd struct {
}

func (*OperationAdd) doOperation(a, b int) int {
	return a + b
}

type OperationSubtract struct {
}

func (*OperationSubtract) doOperation(a, b int) int {
	return a - b
}

type OperationMultiply struct {
}

func (*OperationMultiply) doOperation(a, b int) int {
	return a * b
}

type Context struct {
	strategy Strategy
}

func NewContext(s Strategy) *Context {
	return &Context{strategy: s}
}

func (c *Context) executeStrategy(a, b int) int {
	return c.strategy.doOperation(a, b)
}

测试代码:

func TestStrategy(t *testing.T) {
	c := NewContext(new(OperationAdd))
	if fmt.Sprintf("10 + 5 = %d", c.executeStrategy(10, 5)) != "10 + 5 = 15" {
		t.Fatal("OperationAdd test fail")
	}

	c = NewContext(new(OperationSubtract))
	if fmt.Sprintf("10 - 5 = %d", c.executeStrategy(10, 5)) != "10 - 5 = 5" {
		t.Fatal("OperationSubtract test fail")
	}

	c = NewContext(new(OperationMultiply))
	if fmt.Sprintf("10 * 5 = %d", c.executeStrategy(10, 5)) != "10 * 5 = 50" {
		t.Fatal("OperationMultiply test fail")
	}
}

命令模式

Command 模式,是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

使用场景

UMl

实现

package command

import "fmt"

// Invoker, 调用者

type button struct {
	command command
}

func (b *button) press() {
	b.command.execute()
}

type command interface {
	execute()
}

type onCommand struct {
	device device
}

func (c *onCommand) execute() {
	c.device.on()
}

type offCommand struct {
	device device
}

func (c *offCommand) execute() {
	c.device.off()
}

// Receiver 接收者

type device interface {
	on()
	off()
}

type tv struct {
	isRunning bool
}

func (t *tv) on() {
	t.isRunning = true
	fmt.Println("Turning tv on")
}

func (t *tv) off() {
	t.isRunning = false
	fmt.Println("Turning tv off")
}

测试代码:

package command

import (
	"testing"
)

func TestCommand(t *testing.T) {
	tv := &tv{}
	onCommand := &onCommand{
		device: tv,
	}
	offCommand := &offCommand{
		device: tv,
	}
	onButton := &button{
		command: onCommand,
	}
	onButton.press()
	offButton := &button{
		command: offCommand,
	}
	offButton.press()
}

观察者模式

Observer 模式是一个行为型模式,允许一个 subject 实例发布事件通知给另外多个依赖它的实例(observers)

UML

Mapping

UML actors implementation actors
Subject subject
Concrete Subject item
observer observer
Concrete Observer 1 customer
Client TestObserver

实现

package observer

import "fmt"

type subject interface {
	register(Observer observer)
	deregister(Observer observer)
	notifyAll()
}

type item struct {
	observerList []observer
	name         string
	inStock      bool
}

func newItem(name string) *item {
	return &item{
		name: name,
	}
}

func (i *item) updateAvailability() {
	fmt.Printf("Item %s is now in stock\n", i.name)
	i.inStock = true
	i.notifyAll()
}

func (i *item) register(o observer) {
	i.observerList = append(i.observerList, o)
}

func (i *item) deregister(o observer) {
	i.observerList = removeFromslice(i.observerList, o)
}

func (i *item) notifyAll() {
	for _, observer := range i.observerList {
		observer.update(i.name)
	}
}

func removeFromslice(observerList []observer, observerToRemove observer) []observer {
	observerListLength := len(observerList)
	for i, observer := range observerList {
		if observerToRemove.getID() == observer.getID() {
			observerList[observerListLength-1], observerList[i] = observerList[i], observerList[observerListLength-1]
			return observerList[:observerListLength-1]
		}
	}
	return observerList
}

type observer interface {
	update(string)
	getID() string
}

type customer struct {
	id string
}

func (c *customer) update(itemName string) {
	fmt.Printf("Sending email to customer %s for item %s\n", c.id, itemName)
}

func (c *customer) getID() string {
	return c.id
}

测试代码:

package observer

import (
	"testing"
)

// 测试观察者
func TestObserver(t *testing.T) {
	shirtItem := newItem("Nike Shirt")
	observerFirst := &customer{id: "abc@gmail.com"}
	observerSecond := &customer{id: "xyz@gmail.com"}
	shirtItem.register(observerFirst)
	shirtItem.register(observerSecond)
	shirtItem.updateAvailability()
}

状态模式

State 模式,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。

在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

UML

Mapping

UML actors implementation actors
State Interface state
Concrete State 1 offLightState
Concrete State 2 weakLightState
Concrete State 3 strongLightState
Context Light

实现

使用状态模式实现电灯的程序

package state

import (
	"fmt"
)

type Light struct {
	offLight     state // 关灯
	weakLight    state // 弱光
	strongLight  state // 强光
	currentState state
}

func newLight() *Light {
	l := &Light{}
	offLight := &offLightState{
		light: l,
	}
	weakLight := &weakLightState{
		light: l,
	}
	strongLight := &strongLightState{
		light: l,
	}
	l.offLight = offLight
	l.weakLight = weakLight
	l.strongLight = strongLight
	l.setState(offLight)
	return l
}

func (v *Light) setState(s state) {
	v.currentState = s
}

func (v *Light) getState() state {
	return v.currentState
}

func (v *Light) buttonWasPressed() {
	v.currentState.buttonWasPressed()
}

type state interface {
	buttonWasPressed()
}

// 关灯状态
type offLightState struct {
	light *Light
}

func (i *offLightState) buttonWasPressed() {
	fmt.Println("弱光")
	i.light.setState(i.light.weakLight)
}

// 弱光状态
type weakLightState struct {
	light *Light
}

func (i *weakLightState) buttonWasPressed() {
	fmt.Println("强灯")
	i.light.setState(i.light.strongLight)
}

// 强光状态
type strongLightState struct {
	light *Light
}

func (i *strongLightState) buttonWasPressed() {
	fmt.Println("关灯")
	i.light.setState(i.light.offLight)
}

测试代码:

package state

import (
	// "fmt"
	// "log"
	"testing"
)

func TestState(t *testing.T) {
	l := newLight()
	l.buttonWasPressed()
	l.buttonWasPressed()
	l.buttonWasPressed()
	l.buttonWasPressed()
}