一、创建型(用于方便创建实例)
1. 单例模式
优点:
确保系统中只有一个实例存在,避免多个实例导致的资源冲突或数据不一致问题。例如,数据库连接池、线程池等全局资源管理器适合用单例实现。
减少频繁创建和销毁对象的开销,尤其适用于需要重复使用的对象(如日志记录器、缓存系统)
缺点: 扩展性受限、职责过载
2. 工厂模式
使用场景: 创建对象过程比较复杂, 将复杂的实例创建封装起来,使用时只要通过工厂方法创建(DI)
工厂模式的优点:
- 解耦创建与使用:将对象的创建逻辑从使用逻辑中分离,客户端无需知道具体创建过程。
- 遵循开闭原则:对扩展开放,对修改关闭,添加新产品时无需修改现有客户端代码。
- 提升可维护性:集中管理对象创建逻辑,便于维护和扩展。
- 减少重复代码:统一处理复杂对象创建,避免冗余代码。
- 便于替换和测试:支持依赖注入和模拟对象,提高测试灵活性。
工厂模式的缺点:
- 职责过重:工厂类承担所有对象创建,可能变得臃肿。
- 扩展困难:添加新产品需修改工厂类,违反开闭原则。
- 类数量增加:每个产品需对应一个工厂类,增加系统复杂度。
- 不利于反射:静态工厂方法限制反射机制的使用。
- 抽象工厂适用范围有限:每个具体工厂只能创建一类产品。
典型应用场景
框架设计
ASP.NET Core的依赖注入容器通过工厂模式管理服务实例。数据库访问层
根据配置动态切换SQL Server、MySQL或Oracle的数据访问实现。游戏开发
不同敌人类型(如僵尸、机器人)的创建由工厂统一管理。插件系统
通过工厂加载不同插件的具体实现,避免硬编码依赖。
3. 建造者模式
*使用场景:
a.初始化对象时有必填的参数
b.对象创建后不允许修改属性
建造者模式的优点
封装性好
客户端无需了解对象内部构建细节,只需通过建造者接口操作。灵活性高
支持通过不同建造者类生成不同产品表示,符合开闭原则。可复用性强
建造者类可复用,避免重复代码,提高开发效率。分步构建
允许分步骤构建复杂对象,便于管理和控制构建流程。建造者模式的缺点
增加类数量
需定义抽象建造者、具体建造者和指挥者类,增加系统复杂度。内部修改困难
产品内部结构变化时,需修改所有相关建造者类,维护成本高。构建过程复杂
若对象构建逻辑过于复杂,建造者类可能变得臃肿。
示例:
public class Person
{
public string Name { get; }
public int Age { get; }
public string Address { get; }
private Person(string name, int age, string address)
{
Name = name;
Age = age;
Address = address;
}
public class Builder
{
private string _name;
private int _age;
private string _address;
public Builder WithName(string name)
{
_name = name;
return this;
}
public Builder WithAge(int age)
{
_age = age;
return this;
}
public Builder WithAddress(string address)
{
_address = address;
return this;
}
public Person Build()
{
return new Person(_name, _age, _address);
}
}
}
4. 原型模式(克隆模式)
使用场景: 一个类不同对象的属性没有什么改变,使用克隆的方式来创建后面的类可以提高运行速度(深度克隆/浅度克隆)
* 浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象
using System;
public class Person : ICloneable
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; }
public Person(string name, int age, Address address)
{
Name = name;
Age = age;
Address = address;
}
public object Clone()
{
return new Person(Name, Age, (Address)Address.Clone());
}
public override string ToString()
{
return $"Name: {Name}, Age: {Age}, Address: {Address}";
}
}
public class Address : ICloneable
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public Address(string street, string city, string state)
{
Street = street;
City = city;
State = state;
}
public object Clone()
{
return new Address(Street, City, State);
}
public override string ToString()
{
return $"{Street}, {City}, {State}";
}
}
public class Program
{
public static void Main()
{
Address address = new Address("123 Main St", "Anytown", "CA");
Person person1 = new Person("John Doe", 30, address);
Person person2 = (Person)person1.Clone();
Console.WriteLine(person1);
Console.WriteLine(person2);
person2.Name = "Jane Doe";
person2.Age = 25;
person2.Address.Street = "456 Elm St";
Console.WriteLine(person1);
Console.WriteLine(person2);
}
}
二、结构型模式(7 种)
1、适配器模式 (Adapter)
场景:接口不兼容的类协同工作(如调用第三方API)。
- 需要使用一个已有的类,但其接口不符合需求。
- 想要创建一个可复用的类,与一些不相关或不可预见的类一起工作。
- 需要在不修改现有代码的情况下,使两个不兼容的接口协同工作。
实现:通过包装类转换接口。
示例:假设我们有一个旧的 LegacyRectangle
类,它用于绘制矩形,但它有一个不兼容的接口。而客户端希望使用一个标准的 IShape
接口来绘制形状。
// 客户端期望的接口
public interface IShape
{
void Draw(int x1, int y1, int x2, int y2);
}
// 已有的旧类(不兼容接口)
public class LegacyRectangle
{
public void DrawRectangle(int x, int y, int width, int height)
{
Console.WriteLine($"Drawing rectangle at ({x}, {y}) with width {width} and height {height}");
}
}
// 适配器类,将 LegacyRectangle 转换为 IShape 接口
public class RectangleAdapter : IShape
{
private LegacyRectangle _legacyRectangle;
public RectangleAdapter(LegacyRectangle legacyRectangle)
{
_legacyRectangle = legacyRectangle;
}
// 实现 IShape 接口的方法
public void Draw(int x1, int y1, int x2, int y2)
{
int width = Math.Abs(x2 - x1);
int height = Math.Abs(y2 - y1);
_legacyRectangle.DrawRectangle(x1, y1, width, height);
}
}
// 客户端代码
public class Client
{
public void Main()
{
// 创建旧的 LegacyRectangle 对象
LegacyRectangle legacyRectangle = new LegacyRectangle();
// 使用适配器将其包装为 IShape 接口
IShape shape = new RectangleAdapter(legacyRectangle);
// 客户端通过统一的 IShape 接口调用方法
shape.Draw(10, 10, 50, 50);
}
}
2、装饰器模式 (Decorator)
它允许你动态地给对象添加行为或功能,而无需修改其代码。装饰器模式通过创建一个包装对象(即装饰器)来包裹原始对象,从而实现功能扩展。
装饰器模式的应用场景
- 需要在不修改现有类的情况下动态地扩展其功能。
- 需要为对象添加多个独立的功能,而不是一次性继承所有功能。
- 希望避免使用子类化导致的类爆炸问题。
示例: 我们有一个数据仓储基类,里面有一个 DeleteAsync(long id) 的方法,但是有一个文章仓储删除数据时需要同时删除子内容数据。
public class BaseRepository<T> : IRepository<T> where T : class
{
protected IDbConnection Db => _unitOfWork.Db;
private readonly IUnitOfWork _unitOfWork;
public BaseRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
/// <summary>
/// 根据主键查询单个实体
/// </summary>
/// <returns></returns>
public virtual async Task QueryByIdAsync(object id, )
{
await Db.DeleteAsync<T>(id);
}
}
public class ArticleRepository: BaseRepository<Article>
{
public ArticleRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task DeleteAsync(long id)
{
using (var tran = Db.OpenTransaction())
{
try
{
await Db.DeleteAsync<Article>(x => x.Id == id);
await Db.DeleteAsync<ArticleContent>(x => x.ArticleId == id);
tran.Commit();
}
catch (Exception e)
{
tran.Rollback();
throw;
}
}
}
}
3、代理模式(Proxy Pattern)
它允许你通过一个代理对象来控制对另一个对象的访问。在某些场景下,直接访问目标对象可能会导致性能问题或复杂性增加,这时可以使用代理模式来延迟加载、缓存或保护目标对象。
示例:假设我们需要加载一张大图片,但直接加载可能会消耗大量内存或时间。为了避免不必要的资源浪费,我们希望只有在真正需要显示图片时才加载图片数据。这种情况下,可以使用代理模式来实现延迟加载。
using System;
// 图片接口
public interface IImage
{
void Display();
}
// 真实图片类(目标对象)
public class RealImage : IImage
{
private string _fileName;
public RealImage(string fileName)
{
_fileName = fileName;
LoadFromDisk();
}
private void LoadFromDisk()
{
Console.WriteLine($"Loading image: {_fileName} from disk...");
}
public void Display()
{
Console.WriteLine($"Displaying image: {_fileName}");
}
}
// 图片代理类(代理对象)
public class ImageProxy : IImage
{
private string _fileName;
private RealImage _realImage; // 真实图片对象
public ImageProxy(string fileName)
{
_fileName = fileName;
_realImage = null; // 初始时不加载真实图片
}
public void Display()
{
if (_realImage == null)
{
// 延迟加载:首次调用 Display 时才创建真实图片对象
_realImage = new RealImage(_fileName);
}
_realImage.Display();
}
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
// 创建代理对象
IImage image = new ImageProxy("large_image.jpg");
// 第一次调用 Display,触发延迟加载
Console.WriteLine("First call to Display:");
image.Display();
// 第二次调用 Display,直接使用已加载的真实图片对象
Console.WriteLine("\nSecond call to Display:");
image.Display();
}
}
三、行为型(11 种)
1、观察者模式 (Observer Pattern)
它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。
典型应用场景
- GUI 事件监听器(如按钮点击事件)。
- 发布-订阅系统(如消息队列、事件总线)。
- 数据绑定(如 MVVM 框架中的视图和模型同步)。
using System;
using System.Collections.Generic;
// 观察者接口
public interface IObserver
{
void Update(string message);
}
// 主题接口
public interface ISubject
{
void Attach(IObserver observer);
void Detach(IObserver observer);
void Notify(string message);
}
// 具体主题
public class ConcreteSubject : ISubject
{
private List<IObserver> _observers = new List<IObserver>();
public void Attach(IObserver observer)
{
_observers.Add(observer);
}
public void Detach(IObserver observer)
{
_observers.Remove(observer);
}
public void Notify(string message)
{
foreach (var observer in _observers)
{
observer.Update(message);
}
}
public void SomeBusinessLogic()
{
Console.WriteLine("Subject: Doing some business logic...");
Notify("State has changed!");
}
}
// 具体观察者
public class ConcreteObserver : IObserver
{
private string _name;
public ConcreteObserver(string name)
{
_name = name;
}
public void Update(string message)
{
Console.WriteLine($"Observer {_name} received message: {message}");
}
}
// 客户端代码
class ObserverWork:BackGroundService
{
void ExcuteAsync()
{
var subject = new ConcreteSubject();
var observer1 = new ConcreteObserver("Observer1");
var observer2 = new ConcreteObserver("Observer2");
subject.Attach(observer1);
subject.Attach(observer2);
subject.SomeBusinessLogic();
subject.Detach(observer1);
subject.SomeBusinessLogic();
}
}
2、消费者模式 (Consumer Pattern)
生产者-消费者模型的设计模式。在这种模式中,生产者生成数据,而消费者消费数据。两者通过某种中间机制(如队列、缓冲区)进行解耦。
典型应用场景
- 多线程编程中的任务队列。
- 消息队列系统(如 RabbitMQ、Kafka)。
- 数据流处理(如实时日志分析)。
- 观察者模式更关注的是对象之间的状态同步和通知机制。
- 消费者模式更关注的是生产者和消费者之间的任务分发和解耦。
3、命令模式 (Command)
命令模式的应用场景
- 需要将请求的发起者和执行者解耦。
- 需要支持请求的撤销或重做功能。
- 需要支持命令队列或宏命令(批量执行多个命令)。
- 需要记录日志以便在系统崩溃时重新执行命令。
命令模式的核心思想
- 命令接口:定义一个执行操作的接口。
- 具体命令类:实现命令接口,封装接收者的操作。
- 接收者类:真正执行命令的对象。
- 调用者类(Invoker):负责调用命令对象的执行方法。
- 客户端代码:创建具体的命令对象并将其绑定到接收者。
示例:假设我们正在开发一个智能家居控制系统。用户可以通过遥控器控制灯光的开关、调节亮度等操作。为了支持撤销和重做功能,我们可以使用命令模式来实现。
using System;
using System.Collections.Generic;
// 命令接口
public interface ICommand
{
void Execute(); // 执行命令
void Undo(); // 撤销命令
}
// 接收者类
public class Light
{
private bool _isOn = false;
private int _brightness = 50; // 默认亮度
public void TurnOn()
{
_isOn = true;
Console.WriteLine("Light is ON");
}
public void TurnOff()
{
_isOn = false;
Console.WriteLine("Light is OFF");
}
public void SetBrightness(int brightness)
{
_brightness = brightness;
Console.WriteLine($"Brightness set to {_brightness}");
}
public void ResetBrightness()
{
_brightness = 50;
Console.WriteLine($"Brightness reset to default (50)");
}
}
// 具体命令类:开灯
public class TurnOnLightCommand : ICommand
{
private Light _light;
public TurnOnLightCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.TurnOn();
}
public void Undo()
{
_light.TurnOff();
}
}
// 具体命令类:关灯
public class TurnOffLightCommand : ICommand
{
private Light _light;
public TurnOffLightCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.TurnOff();
}
public void Undo()
{
_light.TurnOn();
}
}
// 具体命令类:设置亮度
public class SetBrightnessCommand : ICommand
{
private Light _light;
private int _brightness;
private int _previousBrightness;
public SetBrightnessCommand(Light light, int brightness)
{
_light = light;
_brightness = brightness;
}
public void Execute()
{
_previousBrightness = _light.GetType().GetProperty("Brightness")?.GetValue(_light, null) as int? ?? 50;
_light.SetBrightness(_brightness);
}
public void Undo()
{
_light.SetBrightness(_previousBrightness);
}
}
// 调用者类(遥控器)
public class RemoteControl
{
private Stack<ICommand> _undoStack = new Stack<ICommand>();
public void PressButton(ICommand command)
{
command.Execute();
_undoStack.Push(command);
}
public void PressUndoButton()
{
if (_undoStack.Count > 0)
{
var command = _undoStack.Pop();
command.Undo();
}
else
{
Console.WriteLine("Nothing to undo.");
}
}
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
Light light = new Light();
ICommand turnOnCommand = new TurnOnLightCommand(light);
ICommand turnOffCommand = new TurnOffLightCommand(light);
ICommand setBrightnessCommand = new SetBrightnessCommand(light, 80);
RemoteControl remote = new RemoteControl();
// 开灯
remote.PressButton(turnOnCommand);
// 设置亮度为 80
remote.PressButton(setBrightnessCommand);
// 关灯
remote.PressButton(turnOffCommand);
// 撤销操作
Console.WriteLine("\nUndoing last action...");
remote.PressUndoButton();
Console.WriteLine("\nUndoing another action...");
remote.PressUndoButton();
Console.WriteLine("\nUndoing one more action...");
remote.PressUndoButton();
Console.WriteLine("\nTrying to undo again...");
remote.PressUndoButton();
}
}
4、责任链模式 (Chain of Responsibility)
场景:动态指定请求处理对象(如审批流程)。
实现:处理器链依次传递请求,直到被处理。