跳到主要内容

设计模式概述

介绍

设计模式是解决软件设计中常见问题的可复用解决方案。它们是经过验证的最佳实践,帮助开发者创建可维护、可扩展和可复用的代码。设计模式不是具体的代码实现,而是解决特定问题的思路和模板。理解和应用设计模式可以提高代码质量,减少常见错误,并促进团队之间的沟通。

原理

设计模式的基本原理

  • 抽象与封装:通过抽象类和接口封装变化,隐藏实现细节
  • 单一职责原则:一个类应该只有一个引起它变化的原因
  • 开放封闭原则:软件实体应该对扩展开放,对修改封闭
  • 里氏替换原则:子类可以替换其父类而不改变程序的正确性
  • 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖抽象
  • 接口隔离原则:客户端不应该依赖它不需要的接口
  • 合成复用原则:优先使用组合而非继承来达到复用的目的
  • 迪米特法则:一个对象应该对其他对象有最少的了解
  • 设计模式的目的:可复用性、可读性、可扩展性、可靠性
  • 设计模式的层次:代码层、设计层、架构层

设计模式的分类

  • 创建型模式:处理对象创建的机制,隐藏创建逻辑
  • 结构型模式:处理类和对象的组合,优化类结构
  • 行为型模式:处理对象之间的通信,优化算法和责任分配
  • 并发型模式:处理多线程编程中的问题
  • 架构型模式:处理软件架构层面的问题

图示

设计模式分类
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ 创建型模式 │ │ 结构型模式 │ │ 行为型模式 │
├─────────────────────┤ ├─────────────────────┤ ├─────────────────────┤
│ 工厂方法模式 │ │ 适配器模式 │ │ 策略模式 │
│ 抽象工厂模式 │ │ 装饰器模式 │ │ 观察者模式 │
│ 单例模式 │ │ 代理模式 │ │ 命令模式 │
│ 建造者模式 │ │ 桥接模式 │ │ 状态模式 │
│ 原型模式 │ │ 组合模式 │ │ 责任链模式 │
│ │ │ 享元模式 │ │ 迭代器模式 │
│ │ │ 外观模式 │ │ 访问者模式 │
│ │ │ │ │ 中介者模式 │
│ │ │ │ │ 备忘录模式 │
│ │ │ │ │ 解释器模式 │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘

SOLID设计原则
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ 单一职责原则 │ │ 开放封闭原则 │ │ 里氏替换原则 │
│ (Single Responsibility) │ (Open/Closed) │ (Liskov Substitution) │
├─────────────────────┤ ├─────────────────────┤ ├─────────────────────┤
│ 一个类只负责一项职责 │ │ 对扩展开放,对修改封闭 │ │ 子类可替换父类 │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘

┌─────────────────────┐ ┌─────────────────────┐
│ 接口隔离原则 │ │ 依赖倒置原则 │
│ (Interface Segregation) │ (Dependency Inversion) │
├─────────────────────┤ ├─────────────────────┤
│ 不强制客户端实现不需要的接口 │ 依赖抽象,不依赖具体实现 │
└─────────────────────┘ └─────────────────────┘

实例

单例模式示例

// 单例模式 - 懒汉式实现
class Singleton {
constructor() {
if (!Singleton.instance) {
this.data = 'Singleton instance data';
Singleton.instance = this;
}
return Singleton.instance;
}

getData() {
return this.data;
}

setData(data) {
this.data = data;
}
}

// 测试单例
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
instance1.setData('New data');
console.log(instance2.getData()); // 'New data'

// 单例模式 - 模块化实现
const singletonModule = (() => {
let instance;

function createInstance() {
return { data: 'Singleton module data' };
}

return {
getInstance: () => {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();

// 测试模块化单例
const moduleInstance1 = singletonModule.getInstance();
const moduleInstance2 = singletonModule.getInstance();
console.log(moduleInstance1 === moduleInstance2); // true

工厂方法模式示例

// 工厂方法模式
class Product {
constructor(name) {
this.name = name;
}

getDescription() {
return `Product: ${this.name}`;
}
}

class ConcreteProductA extends Product {
constructor() {
super('Product A');
}

getDescription() {
return `Concrete ${super.getDescription()}`;
}
}

class ConcreteProductB extends Product {
constructor() {
super('Product B');
}

getDescription() {
return `Concrete ${super.getDescription()}`;
}
}

class Creator {
createProduct(type) {
throw new Error('Method not implemented');
}
}

class ConcreteCreator extends Creator {
createProduct(type) {
switch (type) {
case 'A':
return new ConcreteProductA();
case 'B':
return new ConcreteProductB();
default:
throw new Error(`Unknown product type: ${type}`);
}
}
}

// 测试工厂方法
const creator = new ConcreteCreator();
const productA = creator.createProduct('A');
const productB = creator.createProduct('B');
console.log(productA.getDescription()); // 'Concrete Product: Product A'
console.log(productB.getDescription()); // 'Concrete Product: Product B'

观察者模式示例

// 观察者模式
class Observer {
update(subject) {
throw new Error('Method not implemented');
}
}

class ConcreteObserverA extends Observer {
update(subject) {
console.log(`ConcreteObserverA: Reacted to the state change: ${subject.state}`);
}
}

class ConcreteObserverB extends Observer {
update(subject) {
console.log(`ConcreteObserverB: Reacted to the state change: ${subject.state}`);
}
}

class Subject {
constructor() {
this.observers = [];
this.state = 0;
}

attach(observer) {
this.observers.push(observer);
}

detach(observer) {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}

notify() {
for (const observer of this.observers) {
observer.update(this);
}
}

setState(state) {
console.log(`Subject: setState to ${state}`);
this.state = state;
this.notify();
}
}

// 测试观察者模式
const subject = new Subject();
const observerA = new ConcreteObserverA();
const observerB = new ConcreteObserverB();
subject.attach(observerA);
subject.attach(observerB);
subject.setState(1);
subject.setState(2);
subject.detach(observerB);
subject.setState(3);

装饰器模式示例

// 装饰器模式
class Component {
operation() {
return 'Base Component operation';
}
}

class Decorator extends Component {
constructor(component) {
super();
this.component = component;
}

operation() {
return this.component.operation();
}
}

class ConcreteDecoratorA extends Decorator {
operation() {
return `ConcreteDecoratorA(${super.operation()})`;
}
}

class ConcreteDecoratorB extends Decorator {
operation() {
return `ConcreteDecoratorB(${super.operation()})`;
}
}

// 测试装饰器模式
const component = new Component();
console.log(component.operation()); // 'Base Component operation'

const decoratorA = new ConcreteDecoratorA(component);
console.log(decoratorA.operation()); // 'ConcreteDecoratorA(Base Component operation)'

const decoratorB = new ConcreteDecoratorB(decoratorA);
console.log(decoratorB.operation()); // 'ConcreteDecoratorB(ConcreteDecoratorA(Base Component operation))'

专业解决方案

创建型模式

  • 工厂方法模式:定义一个创建对象的接口,但由子类决定实例化哪个类
  • 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类
  • 单例模式:确保一个类只有一个实例,并提供一个全局访问点
  • 建造者模式:将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示
  • 原型模式:用原型实例指定创建对象的种类,并且通过复制这个原型来创建新的对象

结构型模式

  • 适配器模式:将一个类的接口转换成客户端所期望的另一个接口
  • 装饰器模式:动态地给一个对象添加一些额外的职责
  • 代理模式:为其他对象提供一种代理以控制对这个对象的访问
  • 桥接模式:将抽象部分与实现部分分离,使它们都可以独立地变化
  • 组合模式:将对象组合成树形结构以表示"部分-整体"的层次结构
  • 享元模式:运用共享技术有效地支持大量细粒度的对象
  • 外观模式:为子系统中的一组接口提供一个一致的界面

行为型模式

  • 策略模式:定义一系列算法,把它们封装起来,并使它们可以相互替换
  • 观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新
  • 命令模式:将请求封装成一个对象,从而使你可以用不同的请求参数化客户端
  • 状态模式:允许一个对象在其内部状态改变时改变其行为
  • 责任链模式:为请求创建一个接收者对象的链
  • 迭代器模式:提供一种方法来访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示
  • 访问者模式:表示一个作用于某对象结构中的各元素的操作
  • 中介者模式:用一个中介对象来封装一系列的对象交互
  • 备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
  • 解释器模式:定义语言的语法表示,并解释该语言中的句子

设计模式应用场景

  • 单例模式:日志记录器、配置管理器、数据库连接池
  • 工厂方法模式:创建不同类型的文档、图形界面组件
  • 抽象工厂模式:创建相关产品族,如不同主题的UI组件
  • 建造者模式:创建复杂对象,如汽车、计算机
  • 原型模式:需要复制对象而不依赖其具体类的场景
  • 适配器模式:集成不同接口的系统,如旧系统与新系统的集成
  • 装饰器模式:动态添加功能,如日志、缓存、权限检查
  • 代理模式:远程代理、虚拟代理、保护代理
  • 观察者模式:GUI组件、消息队列、事件处理系统
  • 策略模式:不同的算法实现,如排序、压缩、加密

设计模式最佳实践

  • 理解意图:关注设计模式的意图,而不是具体实现
  • 合适的场景:只在适合的场景下应用设计模式
  • 避免过度设计:不要为了使用设计模式而使用设计模式
  • 简化实现:根据具体需求简化设计模式的实现
  • 组合优于继承:优先使用组合而非继承来复用代码
  • 依赖抽象:依赖抽象接口,而不是具体实现
  • 保持单一职责:确保每个类只负责一项功能
  • 遵循开放封闭原则:对扩展开放,对修改封闭
  • 考虑性能影响:注意设计模式可能带来的性能开销
  • 团队沟通:确保团队成员理解并一致使用设计模式

工具推荐

  • 设计模式库:Java中的Spring框架、Guava库;JavaScript中的lodash、ramda
  • UML工具:StarUML、Lucidchart、Draw.io、Visual Paradigm
  • 代码生成器:JHipster、Yeoman、Spring Roo
  • 静态代码分析:SonarQube、Checkmarx、Fortify
  • 设计模式书籍:《设计模式:可复用面向对象软件的基础》、《Head First 设计模式》、《重构与模式》