程序设计中的主要设计模式通常分为三大类,共23种:
1. 创建型模式(Creational Patterns)
-
单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。
-
工厂方法模式(Factory Method):定义创建对象的接口,由子类决定实例化哪个类。
-
抽象工厂模式(Abstract Factory):提供一个创建一系列相关或依赖对象的接口,而无需指定具体类。
-
建造者模式(Builder):将一个复杂对象的构建与其表示分离,使同样的构建过程可以创建不同的表示。
-
原型模式(Prototype):通过复制现有对象来创建新对象。
2. 结构型模式(Structural Patterns)
-
适配器模式(Adapter):将一个类的接口转换成客户希望的另一个接口。
-
桥接模式(Bridge):将抽象部分与实现部分分离,使它们可以独立变化。
-
组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构。
-
装饰器模式(Decorator):动态地给对象添加职责,相比生成子类更为灵活。
-
外观模式(Facade):为子系统中的一组接口提供一个统一的接口。
-
享元模式(Flyweight):通过共享技术有效地支持大量细粒度对象。
-
代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
3. 行为型模式(Behavioral Patterns)
-
责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者与接收者耦合。
-
命令模式(Command):将请求封装为对象,使你可以用不同的请求对客户进行参数化。
-
解释器模式(Interpreter):给定一个语言,定义其文法的一种表示,并定义一个解释器。
-
迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部表示。
-
中介者模式(Mediator):定义一个中介对象来封装一系列对象之间的交互。
-
备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
-
观察者模式(Observer):定义对象间的一对多依赖关系,当一个对象改变状态时,所有依赖者都会收到通知并自动更新。
-
状态模式(State):允许对象在其内部状态改变时改变其行为。
-
策略模式(Strategy):定义一系列算法,将它们封装起来,并使它们可以互相替换。
-
模板方法模式(Template Method):定义一个操作中的算法骨架,将一些步骤延迟到子类中。
-
访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作,使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
4.命令模式(Command Pattern)解释
命令模式是一种行为型设计模式,它将请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,并支持请求的排队、记录日志、撤销操作等功能。命令模式的核心思想是将“请求”与“执行请求”解耦,使得请求的发起者和执行者之间没有直接的依赖关系。
命令模式的主要角色包括:
-
命令(Command):定义执行操作的接口。
-
具体命令(Concrete Command):实现命令接口,包含接收者对象,并调用接收者的方法来完成具体的操作。
-
接收者(Receiver):知道如何执行具体的操作。
-
调用者(Invoker):持有命令对象,并调用命令对象的执行方法。
-
客户端(Client):创建命令对象并设置其接收者。
通过命令模式,你可以将请求的发起者和执行者解耦,从而支持更灵活的操作,如撤销、重做、日志记录等。
5.命令模式的C#演示代码
下面是一个简单的C#示例,展示了如何使用命令模式来实现一个遥控器控制电灯开关的功能。在这个示例中,遥控器是调用者,电灯是接收者,而开关命令是具体命令。
csharp
using System;
// 命令接口
public interface ICommand
{
void Execute();
void Undo();
}
// 接收者:电灯
public class Light
{
public void On()
{
Console.WriteLine("Light is ON");
}
public void Off()
{
Console.WriteLine("Light is OFF");
}
}
// 具体命令:开灯命令
public class LightOnCommand : ICommand
{
private Light light;
public LightOnCommand(Light light)
{
this.light = light;
}
public void Execute()
{
light.On();
}
public void Undo()
{
light.Off();
}
}
// 具体命令:关灯命令
public class LightOffCommand : ICommand
{
private Light light;
public LightOffCommand(Light light)
{
this.light = light;
}
public void Execute()
{
light.Off();
}
public void Undo()
{
light.On();
}
}
// 调用者:遥控器
public class RemoteControl
{
private ICommand command;
public void SetCommand(ICommand command)
{
this.command = command;
}
public void PressButton()
{
command.Execute();
}
public void PressUndo()
{
command.Undo();
}
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
// 创建接收者(电灯)
Light light = new Light();
// 创建具体命令(开灯和关灯)
ICommand lightOn = new LightOnCommand(light);
ICommand lightOff = new LightOffCommand(light);
// 创建调用者(遥控器)
RemoteControl remote = new RemoteControl();
// 设置开灯命令并执行
remote.SetCommand(lightOn);
remote.PressButton(); // 开灯
// 设置关灯命令并执行
remote.SetCommand(lightOff);
remote.PressButton(); // 关灯
// 撤销操作
remote.PressUndo(); // 撤销关灯,回到开灯状态
}
}
6.代码说明
-
ICommand接口:
-
定义了命令的接口,包含
Execute
方法用于执行命令,以及Undo
方法用于撤销命令。
-
-
Light类(接收者):
-
知道如何执行具体的操作,如开灯和关灯。
-
-
LightOnCommand和LightOffCommand类(具体命令):
-
实现了
ICommand
接口,分别封装了开灯和关灯的操作。 -
在
Execute
方法中调用接收者的方法来完成操作。 -
在
Undo
方法中执行相反的操作以实现撤销功能。
-
-
RemoteControl类(调用者):
-
持有一个命令对象,并通过
PressButton
方法调用命令的执行方法。 -
提供了
PressUndo
方法用于撤销操作。
-
-
客户端代码:
-
创建接收者(电灯)和具体命令(开灯和关灯)。
-
创建调用者(遥控器),并设置不同的命令来执行开灯、关灯和撤销操作。
-
7.输出示例
运行上述代码后,输出如下:
Light is ON
Light is OFF
Light is ON
8.总结
命令模式通过将请求封装为对象,实现了请求的发起者和执行者之间的解耦。它的优点包括:
-
灵活性:可以轻松地扩展新的命令,而无需修改现有代码。
-
支持撤销/重做:通过实现
Undo
方法,可以轻松支持撤销操作。 -
支持日志和事务:可以将命令对象存储在日志中,以便后续重放或回滚。
命令模式适用于需要实现撤销、重做、日志记录等功能的场景,如文本编辑器、遥控器、事务处理系统等。