Contents

Design Pattern

导语
设计模式: 在特定环境下人们解决某类重复出现的一套成功或有效的解决方案.

I. 前言

软件设计模式(Design Pattern),是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。 简单来说,设计模式就是在一定环境下,用固定套路解决问题

设计模式的基础:多态

面向对象设计原则

> 目的:高内聚、低耦合

如何同时提⾼⼀个软件系统的可维护性可复⽤性是⾯向对象设计需要解决的核⼼问题之⼀。 ⾯向对象设计原则为⽀持可维护性复⽤⽽诞⽣,这些原则蕴含在很多设计模式中,它们是从许多设计⽅案中总结出的指导性原则。

  • 单一职责原则: 类的职责单⼀,对外只提供⼀种功能,⽽引起类变化的原因都应该只有⼀个
  • 开闭原则: 类的改动是通过增加代码进⾏的,⽽不是修改源代码
  • 里式代换原则: 任何抽象类出现的地⽅都可以⽤他的实现类进⾏替换,实际就是虚拟机制,语⾔级别实现⾯向对象功能
  • 依赖倒转原则: 依赖于抽象(接⼝),不要依赖具体的实现(类),也就是针对接⼝编程
  • 接口隔离原则: 不应该强迫⽤户的程序依赖他们不需要的接⼝⽅法。⼀个接⼝应该只提供⼀种对外功能,不应该把所有操作都封装到⼀个接⼝中去
  • 合成复用原则: 如果使⽤继承,会导致⽗类的任何变换都可能影响到⼦类的⾏为。如果使⽤对象组合,就降低了这种依赖关系。对于继承和组合,优先使⽤组合
  • 迪米特法则: ⼀个对象应当对其他对象尽可能少的了解,从⽽降低各个对象之间的耦合,提⾼系统的可维护性

II. 分类

  • 创建型(Creational)模式:如何创建对象
模式名称 用途
单例模式
🌟🌟🌟🌟
保证一个类仅有一个实例,并提供一个访问它的全局访问点
简单工厂方法
🌟🌟🌟
通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的基类
抽象工厂方法
🌟🌟🌟🌟🌟
提供一个创建一系列相关或相互依赖的接口,而无需指定它们具体的类
原型模式 ⽤原型实例指定创建对象的种类,并且通过拷⻉这些原型创建新的对象
建造者模式 将⼀个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示
  • 结构型(Structural)模式:如何实现类或对象的组合
模式名称 用途
适配器模式
🌟🌟🌟🌟
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
桥接模式 将抽象部分与实际部分分离,使它们可以独立的变化
组合模式
🌟🌟🌟🌟
将对象组合成树形结构以表示 “部分 - 整体” 的层次结构,使得用户对单个对象和组合对象的使用具有一致性
装饰模式
🌟🌟🌟
动态地给一个对象添加一些额外的职责:就增加功能来说,此模式比生成子类更加灵活
外观模式
🌟🌟🌟🌟🌟
为子系统的一组接口提供一个一致的界面,此模式定义了一个高层次接口,使得这一子系统更容易使用
享元模式 以共享的方式高效的支持大量的细粒度的对象
代理模式 为其他对象提供一种代理以控制这个对象的访问
  • 行为型(Behavioral)模式:类或对象如何交互以及如何分配指责

III. 创建型设计模式

1. 单例模式(Singleton Pattern)

意图:它是一种创建型设计模式,限制了实例化类的对象个数,确保一个类只有一个实例,并且提供一个全局访问点。

warning

Singleton Pattern 同时解决了两个问题,因此违法了单一职责原则:

  1. 保证一个类只用一个实例。
  2. 为该实例提供一个全局访问节点。

应用场景

  • 配置管理器:在应用程序中,配置信息通常需要一个实例来管理,如此可以保证配置信息的一致性
  • 连接池:数据库连接池需要限制数据库连接的数量,以避免过多的连接消耗资源
  • 日志记录器:日志系统通常只需要一个实例来记录应用程序的日志信息,以避免日志信息的冗余和混乱
  • 硬件管理器:对于某些硬件设备,如打印机 / 扫描仪等,可能只需要一个管理器来控制对它们的访问
  • 应用状态管理:在某些应用中,需要全局的管理状态,如用户会话管理或权限验证状态

解决方案

  • 将默认构造函数设为私有,防止其他对象使用单例类的 new 运算符
  • 新建一个静态构建方法作为构造函数:该函数会“偷偷”调用私有构造函数来创建对象,并将其保存到一个静态成员变量中,之后所有对于该函数的调用都将返回这一缓存对象。

单例模式结构

与其他模式的关系

  • 外观模式类通常可以转化为单例模式类,因为在大部分情况下一个外观对象就足够啦
  • 如果能将对象的所有共享状态简化为一个享元对象,那么享元模式就和单例类似,但二者有两个根本性的不同:
    1. 单例只有一个单例实体,但享元类可以有多个实体,各实体的内在状态也可以不同
    2. 单例对象可以是可变的,享元对象不可变
  • 抽象工厂模式生成器模式原型模式都可以用单例来实现

应用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// singleton.go

package designpattern

import "sync"

var once sync.Once

type Singleton struct {
	str string
}

var instance *Singleton

func GetInstance() *Singleton {
	if instance != nil {
		return instance
	}

	once.Do(func() {
		instance = &Singleton{}
	})
	return instance
}

2. 简单工厂模式

亦称:虚拟构造函数、Virtual Constructor、Factory Method

意图:它是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型

NOTE: 由于 Golang 中缺少类和继承等 OOP 特性,因此,无法使用 Go 来实现经典的工厂方法模式,但我们仍能实现基础版本,即简单工厂。

3. 观察者模式(Observer)

亦称:事件订阅者、监听者、Event-Subscriber、Listener

意图:它是一种行为型设计模式,允许定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的其他对象。

拥有一些值得关注的对象通常被称为目标,由于它要将自身状态的变化通知给其他对象,因此也被称为发布者(publisher),而其他关注发布者状态变化的对象被称为订阅者(subscriber)

Observer 核心机制

Observer 模式建议为发布者类添加订阅机制,让每个对象都能订阅或取消订阅发布者事件流。

实际上,该机制包括:

  1. 一个用于存储订阅者对象引用的列表成员变量
  2. 几个用于添加或删除该列表中订阅者的公有方法