马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
前言
1. 操持原则
1.1 单一职责原则
1.2 开放封闭原则
1.3 里氏代替原则
1.4 依赖倒置原则
1.5 接口隔离原则
1.6 合成复用原则
1.6 迪米特原则
2. 单例模式
3. 简单工厂模式
4. 工厂方法模式
4.1 长处
4.2 缺点
5. 抽象工厂模式
5.1 长处
5.2 缺点
6. 制作者模式
6.1 长处
6.2 缺点
7. 原型模式
7.1 长处
7.2 缺点
8. 适配器模式
8.1 长处
8.2 缺点
9. 桥接模式
9.1 长处
9.2 缺点
10. 装饰者模式
10.1 长处
10.2 缺点
11. 组合模式
11.1 长处
11.2 缺点
12. 外观模式
12.1 长处
12.2 缺点
13. 享元模式
13.1 长处
13.2 缺点
14. 代理模式
14.1 长处
14.2 缺点
15. 模板方法模式
15.1 长处
15.2 缺点
16. 命令模式
16.1 长处
16.2 缺点
17. 迭代器模式
17.1 长处
17.2 缺点
18. 观察者模式
18.1 长处
18.2 缺点
19. 中介者模式
19.1 长处
19.2 缺点
20. 状态模式
20.1 长处
20.2 缺点
21. 战略模式
21.1 长处
21.2 缺点
22. 责任链模式
22.1 长处
22.2 缺点
23. 访问者模式
23.1 长处
23.2 缺点
24. 备忘录模式
24.1 长处
24.2 缺点
25. 表明器模式
25.1 长处
25.2 缺点
前言
差别的操持模式有其长处和缺点,并不是全部场景都须要利用相应的操持模式,但如果熟悉操持模式,那么在编程操持时会天然而然的利用到,好比单例模式、工厂方法模式、外观模式、观察者模式、备忘录模式等。
1. 操持原则
1.1 单一职责原则
如果一个类承担的职责过多,就便是把这些职责耦合在一起,一个职责的变革大概会影响到其他的职责,别的,把多个职责耦合在一起,也会影响复用性。
1.2 开放封闭原则
一个软件实体(指的类、函数、模块等)应该对扩展开放,对修改关闭。即每次发生变革时,要通过添加新的代码来增强现有范例的举动,而不是修改原有的代码。
1.3 里氏代替原则
子类必须更换掉它们的父范例。如正方形继续于长方形。
1.4 依赖倒置原则
指的是抽象不应该依赖于细节,细节应该依赖于抽象。高层模块不依赖低层模块,而是依赖接口,否则更换低层模块时,就必须修改高层模块的代码。
1.5 接口隔离原则
利用多个专门的接口比利用单一的总接口要好,也就是说不要让一个单一的接口承担过多的职责。
1.6 合成复用原则
也叫"组合优于继续",也就是说优先利用组合而不是继续来实当代码复用。
- // 基类
- public class Animal
- {
- public void Eat()
- {
- Console.WriteLine("I can eat.");
- }
- }
- // 子类继承 Animal
- public class Bird : Animal
- {
- public void Fly()
- {
- Console.WriteLine("I can fly.");
- }
- }
- class Program
- {
- static void Main()
- {
- Bird bird = new Bird();
- bird.Eat(); // 继承自 Animal
- bird.Fly(); // Bird 自己的方法
- }
- }
复制代码 如果有新的动物,但它不会飞,就不能继续Bird,必须重新界说;如果Animal修改,增加了Walk方法,全部子类都会继续该方法,即使它们不须要。
- // 定义行为接口
- public interface IEat
- {
- void Eat();
- }
- public interface IFly
- {
- void Fly();
- }
- // 具体实现类
- public class EatingBehavior : IEat
- {
- public void Eat()
- {
- Console.WriteLine("I can eat.");
- }
- }
- public class FlyingBehavior : IFly
- {
- public void Fly()
- {
- Console.WriteLine("I can fly.");
- }
- }
- // 通过组合方式创建 Bird,而不是继承
- public class Bird
- {
- private readonly IEat _eatingBehavior;
- private readonly IFly _flyingBehavior;
- public Bird(IEat eatingBehavior, IFly flyingBehavior)
- {
- _eatingBehavior = eatingBehavior;
- _flyingBehavior = flyingBehavior;
- }
- public void Eat() => _eatingBehavior.Eat();
- public void Fly() => _flyingBehavior.Fly();
- }
- class Program
- {
- static void Main()
- {
- Bird bird = new Bird(new EatingBehavior(), new FlyingBehavior());
- bird.Eat(); // 组合的 Eat 方法
- bird.Fly(); // 组合的 Fly 方法
- }
- }
复制代码 最典范的应用就是战略模式,允许对象在运行时动态选择举动。
- // 定义支付接口
- public interface IPaymentStrategy
- {
- void Pay(int amount);
- }
- // 具体支付方式
- public class CreditCardPayment : IPaymentStrategy
- {
- public void Pay(int amount)
- {
- Console.WriteLine($"Paid {amount} using Credit Card.");
- }
- }
- public class PayPalPayment : IPaymentStrategy
- {
- public void Pay(int amount)
- {
- Console.WriteLine($"Paid {amount} using PayPal.");
- }
- }
- // 订单类,使用支付策略
- public class Order
- {
- private readonly IPaymentStrategy _paymentStrategy;
- public Order(IPaymentStrategy paymentStrategy)
- {
- _paymentStrategy = paymentStrategy;
- }
- public void ProcessPayment(int amount)
- {
- _paymentStrategy.Pay(amount);
- }
- }
- class Program
- {
- static void Main()
- {
- // 选择不同的支付方式(可以在运行时改变)
- Order order1 = new Order(new CreditCardPayment());
- order1.ProcessPayment(100); // 使用 Credit Card 付款.
- Order order2 = new Order(new PayPalPayment());
- order2.ProcessPayment(200); // 使用 PayPal 付款.
- }
- }
复制代码 继续适用于"是(is-a)" 的关系,比方Dog继续Animal;
组合适用于"有(has-a)"的关系,比方Bird组合FlyingBehavior。
1.6 迪米特原则
又叫最少知识原则,指的是一个对象应当对其他对象有尽大概少的相识。也就是说,一个模块或对象应尽量少的与其他实体之间发生相互作用,使得体系功能模块相对独立,如许当一个模块修改时,影响的模块就会越少,扩展起来更加轻易。
2. 单例模式
确保一个类只有一个实例,并提供一个全局访问点来获取该实例。它常用于须要全局唯一对象的场景,如设置管理、日记记录、数据库毗连池等。
- public class Singleton
- {
- private static readonly Lazy<Singleton> _lazyInstance = new Lazy<Singleton>(() => new Singleton());
- private Singleton() { }
- public static Singleton Instance
- {
- get
- {
- return _lazyInstance.Value;
- }
- }
- }
复制代码 3. 简单工厂模式
即通过一个工厂类来封装对象的创建过程,客户端无需知道具体的类名,只需通过工厂类即可获取所需的对象。
简单工厂模式并不属于GoF的23种操持模式,但它是一种常用的编程风俗。
简单工厂模式通过封装对象的创建逻辑,简化了客户端的代码,并实现了客户端与具体产物类的解耦。只管它违反了开闭原则,但在对象创建逻辑简单且产物范例较少的场景下,仍然是一个非常有效的操持模式。
4. 工厂方法模式
它界说了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化耽误到子类,从而实现了对象的创建与利用的分离。
工厂方法模式通常包罗以下几个脚色:
1、抽象工厂(Creator):界说工厂方法,返回一个抽象产物范例的对象。
2、具体工厂(Concrete Creator):实现工厂方法,返回具体产物范例的对象。
3、抽象产物(Product):界说产物的接口或抽象类。
4、具体产物(Concrete Product):实现抽象产物的具体类。
什么意思呢?假设我们正在开辟一个付出体系,支持多种付出方式,如名誉卡付出、付出宝付出和微信付出。我们可以利用工厂方法模式来实现这个体系。
①、界说抽象产物
- public interface IPayment
- {
- void Pay(decimal amount);
- }
复制代码 ②、界说具体产物
- public class CreditCardPayment : IPayment
- {
- public void Pay(decimal amount)
- {
- Console.WriteLine($"Paying {amount} via Credit Card.");
- }
- }
- public class AlipayPayment : IPayment
- {
- public void Pay(decimal amount)
- {
- Console.WriteLine($"Paying {amount} via Alipay.");
- }
- }
- public class WechatPayment : IPayment
- {
- public void Pay(decimal amount)
- {
- Console.WriteLine($"Paying {amount} via Wechat.");
- }
- }
复制代码 ③、界说抽象工厂
- public abstract class PaymentFactory
- {
- public abstract IPayment CreatePayment();
- }
复制代码 ④、界说具体工厂
- public class CreditCardPaymentFactory : PaymentFactory
- {
- public override IPayment CreatePayment()
- {
- return new CreditCardPayment();
- }
- }
- public class AlipayPaymentFactory : PaymentFactory
- {
- public override IPayment CreatePayment()
- {
- return new AlipayPayment();
- }
- }
- public class WechatPaymentFactory : PaymentFactory
- {
- public override IPayment CreatePayment()
- {
- return new WechatPayment();
- }
- }
复制代码 ⑤、 客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- PaymentFactory creditCardFactory = new CreditCardPaymentFactory();
- IPayment creditCardPayment = creditCardFactory.CreatePayment();
- creditCardPayment.Pay(100.00m);
- PaymentFactory alipayFactory = new AlipayPaymentFactory();
- IPayment alipayPayment = alipayFactory.CreatePayment();
- alipayPayment.Pay(200.00m);
- PaymentFactory wechatFactory = new WechatPaymentFactory();
- IPayment wechatPayment = wechatFactory.CreatePayment();
- wechatPayment.Pay(300.00m);
- }
- }
复制代码 抽象工厂和抽象产物通常是接口(大概抽象类) ,而具体工厂和具体产物是类,它们分别实现了这些接口或继续了抽象类。
工厂和产物的关系是创建与被创建的关系,工厂负责创建产物,而产物是工厂创建的对象。
- +-------------------+ +-------------------+
- | 客户端 (Client) | | 抽象工厂 (Factory) |
- | | | |
- | 使用工厂创建产品 | <----> | 创建产品的方法 |
- +-------------------+ +-------------------+
- ^
- | 实现
- |
- +-------------------+
- | 具体工厂 (Concrete Factory) |
- | |
- | 实现创建产品的逻辑 |
- +-------------------+
- ^
- | 创建
- |
- +-------------------+
- | 抽象产品 (Product) |
- | |
- | 定义产品的行为 |
- +-------------------+
- ^
- | 实现
- |
- +-------------------+
- | 具体产品 (Concrete Product) |
- | |
- | 实现具体的功能 |
- +-------------------+
复制代码 4.1 长处
1、符合开闭原则:新增付出方式时,只需添加新的具体工厂类和具体产物类,无需修改现有代码。
2、解耦:客户端与具体付出方式解耦,客户端只需知道付出的抽象范例。
3、可扩展性:易于扩展新的付出方式。
4.2 缺点
1、类的数量增加:每新增一个付出方式,都须要新增一个具体工厂类,导致类的数量增加。
2、复杂性增加:对于简单对象的创建,利用工厂方法模式大概会增加体系的复杂性。
5. 抽象工厂模式
它提供了一种创建一系列相干或相互依赖对象的接口,而无需指定它们的具体类。抽象工厂模式是工厂方法模式的扩展,它关注的是产物族(一组相干的产物),而不仅仅是单个产物。
假设我们正在开辟一个跨平台的 GUI 库,支持 Windows 和 Mac 两种风格。每种风格都有按钮、文本框和下拉菜单。
①、界说抽象产物
- // 按钮接口
- public interface IButton
- {
- void Render();
- }
- // 文本框接口
- public interface ITextBox
- {
- void Render();
- }
- // 下拉菜单接口
- public interface IComboBox
- {
- void Render();
- }
复制代码 ②、界说具体产物
- // Windows风格的产品
- public class WindowsButton : IButton
- {
- public void Render()
- {
- Console.WriteLine("渲染一个 Windows 风格的按钮");
- }
- }
- public class WindowsTextBox : ITextBox
- {
- public void Render()
- {
- Console.WriteLine("渲染一个 Windows 风格的文本框");
- }
- }
- public class WindowsComboBox : IComboBox
- {
- public void Render()
- {
- Console.WriteLine("渲染一个 Windows 风格的下拉菜单");
- }
- }
复制代码- // Mac风格的产品
- public class MacButton : IButton
- {
- public void Render()
- {
- Console.WriteLine("渲染一个 Mac 风格的按钮");
- }
- }
- public class MacTextBox : ITextBox
- {
- public void Render()
- {
- Console.WriteLine("渲染一个 Mac 风格的文本框");
- }
- }
- public class MacComboBox : IComboBox
- {
- public void Render()
- {
- Console.WriteLine("渲染一个 Mac 风格的下拉菜单");
- }
- }
复制代码 ③、界说抽象工厂
- public interface IGuiFactory
- {
- IButton CreateButton();
- ITextBox CreateTextBox();
- IComboBox CreateComboBox();
- }
复制代码 ④、界说具体工厂
- // Windows风格的工厂
- public class WindowsFactory : IGuiFactory
- {
- public IButton CreateButton()
- {
- return new WindowsButton();
- }
- public ITextBox CreateTextBox()
- {
- return new WindowsTextBox();
- }
- public IComboBox CreateComboBox()
- {
- return new WindowsComboBox();
- }
- }
复制代码- // Mac风格的工厂
- public class MacFactory : IGuiFactory
- {
- public IButton CreateButton()
- {
- return new MacButton();
- }
- public ITextBox CreateTextBox()
- {
- return new MacTextBox();
- }
- public IComboBox CreateComboBox()
- {
- return new MacComboBox();
- }
- }
复制代码 ⑤、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建 Windows 风格的 GUI
- IGuiFactory windowsFactory = new WindowsFactory();
- IButton windowsButton = windowsFactory.CreateButton();
- ITextBox windowsTextBox = windowsFactory.CreateTextBox();
- IComboBox windowsComboBox = windowsFactory.CreateComboBox();
- windowsButton.Render();
- windowsTextBox.Render();
- windowsComboBox.Render();
- // 创建 Mac 风格的 GUI
- IGuiFactory macFactory = new MacFactory();
- IButton macButton = macFactory.CreateButton();
- ITextBox macTextBox = macFactory.CreateTextBox();
- IComboBox macComboBox = macFactory.CreateComboBox();
- macButton.Render();
- macTextBox.Render();
- macComboBox.Render();
- }
- }
复制代码 5.1 长处
1、一致性:
抽象工厂模式确保创建的产物族是一致的。比方,全部 Windows 风格的产物一起利用。
2、解耦:
客户端只依赖抽象工厂和抽象产物,不依赖具体实现。
3、可扩展性:
新增产物族时,只需添加新的具体工厂和具体产物类,而无需修改现有代码。
4、符合开闭原则:
对扩展开放,对修改关闭。
5.2 缺点
1、复杂性增加:
每新增一个产物族,都须要添加多个具体产物类和具体工厂类,导致类的数量增加。
2、不易支持新范例产物:
如果须要在产物族中新增一种产物范例(如复选框),则须要修改抽象工厂及其全部具体工厂。
6. 制作者模式
制作者模式是一种创建型操持模式,它允许你分步调创建复杂对象。制作者模式将一个复杂对象的构建过程与其表现分离,使得同样的构建过程可以创建差别的表现。
比方,构建电脑、汽车、房屋等须要多个步调的对象;构建差别范例的电脑(高性能、普通、低配等);构建过程中须要动态调解某些步调。
假设我们正在构建一个电脑,电脑由 CPU、内存、硬盘和显卡组成。我们可以利用制作者模式来分步调构建电脑。
①、界说产物
- public class Computer
- {
- public string CPU { get; set; }
- public string Memory { get; set; }
- public string HardDisk { get; set; }
- public string GPU { get; set; }
- public void Display()
- {
- Console.WriteLine($"CPU: {CPU}");
- Console.WriteLine($"Memory: {Memory}");
- Console.WriteLine($"HardDisk: {HardDisk}");
- Console.WriteLine($"GPU: {GPU}");
- }
- }
复制代码 ②、界说抽象制作者
- public interface IComputerBuilder
- {
- void BuildCPU();
- void BuildMemory();
- void BuildHardDisk();
- void BuildGPU();
- Computer GetComputer();
- }
复制代码 ③、界说具体制作者
- // 高性能电脑建造者
- public class HighPerformanceComputerBuilder : IComputerBuilder
- {
- private Computer _computer = new Computer();
- public void BuildCPU()
- {
- _computer.CPU = "Intel Core i9";
- }
- public void BuildMemory()
- {
- _computer.Memory = "32GB DDR5";
- }
- public void BuildHardDisk()
- {
- _computer.HardDisk = "1TB SSD";
- }
- public void BuildGPU()
- {
- _computer.GPU = "NVIDIA RTX 3090";
- }
- public Computer GetComputer()
- {
- return _computer;
- }
- }
复制代码- // 普通电脑建造者
- public class StandardComputerBuilder : IComputerBuilder
- {
- private Computer _computer = new Computer();
- public void BuildCPU()
- {
- _computer.CPU = "Intel Core i5";
- }
- public void BuildMemory()
- {
- _computer.Memory = "16GB DDR4";
- }
- public void BuildHardDisk()
- {
- _computer.HardDisk = "512GB SSD";
- }
- public void BuildGPU()
- {
- _computer.GPU = "NVIDIA GTX 1660";
- }
- public Computer GetComputer()
- {
- return _computer;
- }
- }
复制代码 ④、界说指挥者
- public class ComputerDirector
- {
- private IComputerBuilder _builder;
- public ComputerDirector(IComputerBuilder builder)
- {
- _builder = builder;
- }
- public void ConstructComputer()
- {
- _builder.BuildCPU();
- _builder.BuildMemory();
- _builder.BuildHardDisk();
- _builder.BuildGPU();
- }
- public Computer GetComputer()
- {
- return _builder.GetComputer();
- }
- }
复制代码 ⑤、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 构建高性能电脑
- IComputerBuilder highPerformanceBuilder = new HighPerformanceComputerBuilder();
- ComputerDirector highPerformanceDirector = new ComputerDirector(highPerformanceBuilder);
- highPerformanceDirector.ConstructComputer();
- Computer highPerformanceComputer = highPerformanceDirector.GetComputer();
- highPerformanceComputer.Display();
- Console.WriteLine();
- // 构建普通电脑
- IComputerBuilder standardBuilder = new StandardComputerBuilder();
- ComputerDirector standardDirector = new ComputerDirector(standardBuilder);
- standardDirector.ConstructComputer();
- Computer standardComputer = standardDirector.GetComputer();
- standardComputer.Display();
- }
- }
复制代码 6.1 长处
1、分步调构建:
制作者模式允许你分步调构建复杂对象,使得构建过程更加清楚和可控。
2、解耦:
将构建过程与表现分离,客户端无需知道具体的构建细节。
3、复用性:
同样的构建过程可以创建差别的表现。
4、机动性:
可以轻松扩展新的具体制作者来支持新的产物范例。
6.2 缺点
1、复杂性增加:
每新增一个产物范例,都须要添加新的具体制作者类,导致类的数量增加。
2、适用范围有限:
制作者模式适用于构建复杂对象,如果对象非常简单,利用制作者模式大概会增加不须要的复杂性。
7. 原型模式
原型模式允许通过复制现有对象来创建新对象,而无需依赖于类的构造函数。原型模式的核心头脑是通过克隆(Clone)来创建对象,而不是通过构造函数。
如果你界说了一个接口,接口包罗克隆;实现了接口,实现了克隆;利用实现类的克隆来创建对象而不是构造函数。那么这就足以分析你利用了原型模式的操持模式。
假设我们有一个形状(Shape)类,它包罗一个Clone方法,用于复制自身。
①、界说原型接口
- public interface IShape
- {
- IShape Clone();
- void Draw();
- }
复制代码 ②、界说具体原型
- // 圆形
- public class Circle : IShape
- {
- public int Radius { get; set; }
- public Circle(int radius)
- {
- Radius = radius;
- }
- public IShape Clone()
- {
- return new Circle(Radius);
- }
- public void Draw()
- {
- Console.WriteLine($"绘制一个圆形,半径:{Radius}");
- }
- }
复制代码- // 矩形
- public class Rectangle : IShape
- {
- public int Width { get; set; }
- public int Height { get; set; }
- public Rectangle(int width, int height)
- {
- Width = width;
- Height = height;
- }
- public IShape Clone()
- {
- return new Rectangle(Width, Height);
- }
- public void Draw()
- {
- Console.WriteLine($"绘制一个矩形,宽度:{Width},高度:{Height}");
- }
- }
复制代码 ③、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建原型对象
- IShape circlePrototype = new Circle(10);
- IShape rectanglePrototype = new Rectangle(20, 30);
- // 克隆原型对象
- IShape clonedCircle = circlePrototype.Clone();
- IShape clonedRectangle = rectanglePrototype.Clone();
- // 使用克隆对象
- clonedCircle.Draw();
- clonedRectangle.Draw();
- }
- }
复制代码 7.1 长处
1、简化对象创建:
通过克隆现有对象来创建新对象,制止了复杂的构造函数调用。
2、性能提升:
如果对象的创建本钱较高(如须要从数据库加载数据),克隆可以明显进步性能。
3、动态设置对象:
可以在运行时动态设置对象,然后通过克隆创建新对象。
4、减少子类数量:
通过克隆现有对象,可以减少子类的数量。
7.2 缺点
1、深拷贝与浅拷贝标题:
如果对象包罗引用范例的字段,克隆时须要注意深拷贝和浅拷贝的标题。
2、复杂性增加:
如果对象的克隆逻辑复杂,大概会导致代码难以维护。
8. 适配器模式
适配器模式允许将一个类的接口转换成客户端所盼望的另一个接口。适配器模式通常用于解决接口不兼容的标题,使得原本由于接口不匹配而无法一起工作的类可以协同工作。
适配器模式的核心就是为相识决新接口与旧接口不兼容的标题,使得原本由于接口不匹配而无法一起工作(如传入参数不一致、功能不一致等)的类可以协同工作。
假设我们有一个旧的日记体系(OldLogger),它的接口与新的日记体系(NewLogger)不兼容。我们可以利用适配器模式来将旧的日记体系适配到新的日记体系中。
①、界说目的接口
- public interface INewLogger
- {
- void Log(string message);
- }
复制代码 ②、界说适配者
- public class OldLogger
- {
- public void LogMessage(string message)
- {
- Console.WriteLine($"Old Logger: {message}");
- }
- }
复制代码 ③、界说适配器
- public class LoggerAdapter : INewLogger
- {
- private OldLogger _oldLogger;
- public LoggerAdapter(OldLogger oldLogger)
- {
- _oldLogger = oldLogger;
- }
- public void Log(string message)
- {
- // 调用适配者的方法
- _oldLogger.LogMessage(message);
- }
- }
复制代码 ④、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建适配者对象
- OldLogger oldLogger = new OldLogger();
- // 创建适配器对象
- INewLogger loggerAdapter = new LoggerAdapter(oldLogger);
- // 使用适配器对象
- loggerAdapter.Log("This is a log message.");
- }
- }
复制代码 8.1 长处
1、解耦
适配器模式将客户端与适配者解耦,客户端只依赖目的接口。
2、复用性
可以复用现有的类,而无需修改其代码。
3、机动性
可以轻松地扩展新的适配器来支持新的适配者。
8.2 缺点
1、复杂性增加
每新增一个适配者,都须要添加一个新的适配器类,导致类的数量增加。
2、太过利用大概导致体系杂乱
如果体系中大量利用适配器模式,大概会导致体系结构复杂,难以维护。
9. 桥接模式
桥接模式的核心头脑是将抽象部分与实现部分分离,使它们可以独立变革,再通过组合而不是继续来毗连抽象部分和实现部分,从而制止类爆炸标题,并进步体系的机动性。
假设我们正在开辟一个图形绘制库,支持多种形状(如圆形、矩形)和多种颜色(如红色、蓝色)。我们可以利用桥接模式来将形状和颜色分离。
①、界说实现部分(颜色)
- public interface IColor
- {
- string Fill();
- }
复制代码 ②、界说具体实现部分(红色和蓝色)
- public class Red : IColor
- {
- public string Fill()
- {
- return "红色";
- }
- }
- public class Blue : IColor
- {
- public string Fill()
- {
- return "蓝色";
- }
- }
复制代码 ③、界说抽象部分(形状)
- public abstract class Shape
- {
- protected IColor _color;
- public Shape(IColor color)
- {
- _color = color;
- }
- public abstract string Draw();
- }
复制代码 ④、界说扩展抽象部分(圆形和矩形)
- public class Circle : Shape
- {
- public Circle(IColor color) : base(color)
- {
- }
- public override string Draw()
- {
- return $"绘制一个{_color.Fill()}的圆形";
- }
- }
- public class Rectangle : Shape
- {
- public Rectangle(IColor color) : base(color)
- {
- }
- public override string Draw()
- {
- return $"绘制一个{_color.Fill()}的矩形";
- }
- }
复制代码 ⑤、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建具体实现部分(颜色)
- IColor red = new Red();
- IColor blue = new Blue();
- // 创建扩展抽象部分(形状)
- Shape redCircle = new Circle(red);
- Shape blueRectangle = new Rectangle(blue);
- // 绘制形状
- Console.WriteLine(redCircle.Draw());
- Console.WriteLine(blueRectangle.Draw());
- }
- }
复制代码 如果利用继续来实现,会导致类爆炸标题。这是因为形状和颜色是两个独立的维度,每个维度的变革都会导致类的数量成倍增加。
假设我们有以下两个维度:
1、形状:圆形、矩形。
2、颜色:红色、蓝色。
如果利用继续,我们须要为每一种形状和颜色的组合创建一个类。比方:红色圆形、蓝色圆形、红色矩形、蓝色矩形。如果有更多的形状和颜色,类的数量会迅速增加。同时如果利用继续也是不分离抽象与实现的一个反面例子,也就是每一种搭配都要创建一个类。
9.1 长处
1、分离抽象与实现
桥接模式将抽象部分与实现部分分离,使它们可以独立变革。
2、制止类爆炸
通过组合而不是继续来毗连抽象部分和实现部分,制止了类爆炸标题。
3、进步机动性
可以动态地切换抽象部分和实现部分。
4、符合开闭原则
抽象部分和实现部分可以独立扩展,而无需修改现有代码。
9.2 缺点
1、复杂性增加
桥接模式引入了更多的类和对象,增加了体系的复杂性。
2、操持难度增加
须要精确地辨认抽象部分和实现部分,增加了操持的难度。
10. 装饰者模式
装饰者模式允许你通过将对象放入包罗举动的特殊封装对象中来为原对象动态添加新的举动。装饰者模式的核心头脑是在不修改原有对象的情况下,动态地扩展其功能。
假设我们有一个咖啡店体系,支持多种咖啡(如美式咖啡、拿铁)和多种调料(如牛奶、糖)。我们可以利用装饰者模式来动态地为咖啡添加调料。
①、界说组件接口
- public interface ICoffee
- {
- string GetDescription();
- double GetCost();
- }
复制代码 ②、界说具体组件
- // 美式咖啡
- public class Americano : ICoffee
- {
- public string GetDescription()
- {
- return "美式咖啡";
- }
- public double GetCost()
- {
- return 2.0;
- }
- }
复制代码- // 拿铁
- public class Latte : ICoffee
- {
- public string GetDescription()
- {
- return "拿铁";
- }
- public double GetCost()
- {
- return 3.0;
- }
- }
复制代码 ③、界说装饰者
- public abstract class CoffeeDecorator : ICoffee
- {
- protected ICoffee _coffee;
- public CoffeeDecorator(ICoffee coffee)
- {
- _coffee = coffee;
- }
- public virtual string GetDescription()
- {
- return _coffee.GetDescription();
- }
- public virtual double GetCost()
- {
- return _coffee.GetCost();
- }
- }
复制代码 ④、界说具体装饰者
- // 牛奶
- public class Milk : CoffeeDecorator
- {
- public Milk(ICoffee coffee) : base(coffee)
- {
- }
- public override string GetDescription()
- {
- return _coffee.GetDescription() + ",加牛奶";
- }
- public override double GetCost()
- {
- return _coffee.GetCost() + 0.5;
- }
- }
复制代码- // 糖
- public class Sugar : CoffeeDecorator
- {
- public Sugar(ICoffee coffee) : base(coffee)
- {
- }
- public override string GetDescription()
- {
- return _coffee.GetDescription() + ",加糖";
- }
- public override double GetCost()
- {
- return _coffee.GetCost() + 0.2;
- }
- }
复制代码 ⑤、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建具体组件(美式咖啡)
- ICoffee coffee = new Americano();
- Console.WriteLine($"{coffee.GetDescription()},价格:{coffee.GetCost()}");
- // 动态添加调料(牛奶)
- coffee = new Milk(coffee);
- Console.WriteLine($"{coffee.GetDescription()},价格:{coffee.GetCost()}");
- // 动态添加调料(糖)
- coffee = new Sugar(coffee);
- Console.WriteLine($"{coffee.GetDescription()},价格:{coffee.GetCost()}");
- }
- }
复制代码 10.1 长处
1、动态扩展功能
装饰者模式允许你在运行时动态地为对象添加功能,而不须要修改原有对象的代码。
2、符合开闭原则
对扩展开放,对修改关闭。新增功能时,只需添加新的装饰者类,而无需修改现有代码。
3、机动性
可以动态地组合多个装饰者来扩展对象的功能。
10.2 缺点
1、复杂性增加
每新增一个装饰者,都须要添加一个新的类,导致类的数量增加。
2、调试困难
由于装饰者模式会生成多层嵌套的对象,调试时大概会比力困难。
11. 组合模式
组合模式允许你将对象组合成树形结构以表现“部分—团体”的条理结构。组合模式使得客户端可以同一对待单个对象和组合对象。
假设我们正在开辟一个文件体系,文件体系由文件和文件夹组成。文件夹可以包罗文件或其他文件夹。我们可以利用组合模式来表现文件体系的条理结构。
①、界说组件接口
- public interface IFileSystemComponent
- {
- void Display(int depth);
- }
复制代码 ②、界说叶子(文件)
- public class File : IFileSystemComponent
- {
- private string _name;
- public File(string name)
- {
- _name = name;
- }
- public void Display(int depth)
- {
- Console.WriteLine(new string('-', depth) + _name);
- }
- }
复制代码 ③、界说容器(文件夹)
- public class Folder : IFileSystemComponent
- {
- private string _name;
- private List<IFileSystemComponent> _components = new List<IFileSystemComponent>();
- public Folder(string name)
- {
- _name = name;
- }
- public void AddComponent(IFileSystemComponent component)
- {
- _components.Add(component);
- }
- public void RemoveComponent(IFileSystemComponent component)
- {
- _components.Remove(component);
- }
- public void Display(int depth)
- {
- Console.WriteLine(new string('-', depth) + _name);
- foreach (var component in _components)
- {
- component.Display(depth + 2);
- }
- }
- }
复制代码 ④、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建文件
- IFileSystemComponent file1 = new File("文件1.txt");
- IFileSystemComponent file2 = new File("文件2.txt");
- IFileSystemComponent file3 = new File("文件3.txt");
- // 创建文件夹
- Folder folder1 = new Folder("文件夹1");
- Folder folder2 = new Folder("文件夹2");
- // 将文件添加到文件夹1
- folder1.AddComponent(file1);
- folder1.AddComponent(file2);
- // 将文件夹1和文件3添加到文件夹2
- folder2.AddComponent(folder1);
- folder2.AddComponent(file3);
- // 显示文件系统结构
- folder2.Display(0);
- }
- }
复制代码 11.1 长处
1、同一对待
客户端可以同一对待单个对象和组合对象,无需区分它们。
2、简化客户端代码
客户端不须要关心处置惩罚的是单个对象照旧组合对象,代码更加简便。
3、易于扩展
可以轻松地新增新的叶子或容器节点,而无需修改现有代码。
11.2 缺点
1、操持复杂性增加
组合模式引入了更多的类和对象,增加了体系的复杂性。
2、限定范例
组合模式要责备部组件(叶子和容器)实现相同的接口,这大概限定了组件的范例。
12. 外观模式
外观模式提供了一个同一的接口,用来访问子体系中的一群接口。外观模式界说了一个高层接口,让子体系更轻易利用。客户端只须要与外观对象交互,而不须要直接与子体系中的多个对象交互。
可以说外观模式是哪怕我们不知道有这个操持模式,在编程时也会下意识的利用它,即将多个子体系的复杂操纵封装在一个同一的接口中,客户端只须要关注这个同一的接口,而不须要相识子体系的内部细节。
假设我们有一个家庭影院体系,包罗多个装备(如投影仪、音响、灯光等)。我们可以利用外观模式来简化操纵。
①、界说子体系(装备)
- // 投影仪
- public class Projector
- {
- public void On()
- {
- Console.WriteLine("投影仪打开");
- }
- public void Off()
- {
- Console.WriteLine("投影仪关闭");
- }
- public void SetInput(string input)
- {
- Console.WriteLine($"投影仪输入设置为:{input}");
- }
- }
复制代码- // 音响
- public class SoundSystem
- {
- public void On()
- {
- Console.WriteLine("音响打开");
- }
- public void Off()
- {
- Console.WriteLine("音响关闭");
- }
- public void SetVolume(int volume)
- {
- Console.WriteLine($"音响音量设置为:{volume}");
- }
- }
复制代码- // 灯光
- public class Lights
- {
- public void Dim(int level)
- {
- Console.WriteLine($"灯光调暗到:{level}%");
- }
- public void On()
- {
- Console.WriteLine("灯光打开");
- }
- public void Off()
- {
- Console.WriteLine("灯光关闭");
- }
- }
复制代码 ②、界说外观
- public class HomeTheaterFacade
- {
- private Projector _projector;
- private SoundSystem _soundSystem;
- private Lights _lights;
- public HomeTheaterFacade(Projector projector, SoundSystem soundSystem, Lights lights)
- {
- _projector = projector;
- _soundSystem = soundSystem;
- _lights = lights;
- }
- public void WatchMovie(string movie)
- {
- Console.WriteLine("准备观看电影...");
- _lights.Dim(10);
- _projector.On();
- _projector.SetInput("HDMI");
- _soundSystem.On();
- _soundSystem.SetVolume(50);
- Console.WriteLine($"开始播放电影:{movie}");
- }
- public void EndMovie()
- {
- Console.WriteLine("结束观看电影...");
- _projector.Off();
- _soundSystem.Off();
- _lights.On();
- }
- }
复制代码 ③、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建子系统对象
- Projector projector = new Projector();
- SoundSystem soundSystem = new SoundSystem();
- Lights lights = new Lights();
- // 创建外观对象
- HomeTheaterFacade homeTheater = new HomeTheaterFacade(projector, soundSystem, lights);
- // 使用外观对象
- homeTheater.WatchMovie("星际穿越");
- Console.WriteLine();
- homeTheater.EndMovie();
- }
- }
复制代码 12.1 长处
1、简化接口
外观模式通过提供一个简化的接口,隐藏了子体系的复杂性。
2、解耦
客户端只须要与外观对象交互,而不须要直接与子体系中的多个对象交互。
3、进步可维护性
外观模式将客户端与子体系解耦,使得子体系的变革不会影响到客户端。
12.2 缺点
1、不符合开闭原则
如果子体系发生变革,大概须要修改外观类。
2、太过利用大概导致体系杂乱
如果体系中大量利用外观模式,大概会导致体系结构复杂,难以维护。
13. 享元模式
享元模式通过共享对象来有效地支持大量细粒度的对象。享元模式的核心头脑是将对象的共享部分(内部状态)与不可共享部分(外部状态)分离,从而减少内存占用和进步性能。
当多个对象共享相同的属性(内部状态)时,通过一个工厂来管理这些共享属性,制止重复创建,从而减少内存占用。
假设我们正在开辟一个文本编辑器,须要处置惩罚大量的字符对象。字符对象的字体和巨细是内部状态,而字符的位置是外部状态。我们可以利用享元模式来共享字符对象的内部状态。
①、界说享元接口
- public interface ICharacter
- {
- void Display(int positionX, int positionY);
- }
复制代码 ②、界说具体享元
- public class Character : ICharacter
- {
- private char _symbol;
- private string _font;
- private int _size;
- public Character(char symbol, string font, int size)
- {
- _symbol = symbol;
- _font = font;
- _size = size;
- }
- public void Display(int positionX, int positionY)
- {
- Console.WriteLine($"字符:{_symbol},字体:{_font},大小:{_size},位置:({positionX}, {positionY})");
- }
- }
复制代码 ③、界说享元工厂
- public class CharacterFactory
- {
- private Dictionary<char, ICharacter> _characters = new Dictionary<char, ICharacter>();
- public ICharacter GetCharacter(char symbol, string font, int size)
- {
- if (!_characters.ContainsKey(symbol))
- {
- _characters[symbol] = new Character(symbol, font, size);
- }
- return _characters[symbol];
- }
- }
复制代码 ④、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建享元工厂
- CharacterFactory factory = new CharacterFactory();
- // 创建字符对象
- ICharacter charA = factory.GetCharacter('A', "Arial", 12);
- ICharacter charB = factory.GetCharacter('B', "Times New Roman", 14);
- ICharacter charA2 = factory.GetCharacter('A', "Arial", 12);
- // 显示字符对象
- charA.Display(10, 20);
- charB.Display(30, 40);
- charA2.Display(50, 60);
- // 检查是否共享对象
- Console.WriteLine($"charA 和 charA2 是否是同一个对象:{charA == charA2}");
- }
- }
复制代码 如果倒霉用享元模式:
13.1 长处
1、减少内存占用
通过共享对象的内部状态,减少了内存占用。
2、进步性能
减少了对象的创建和烧毁次数,进步了性能。
3、机动性
可以动态地添加新的享元对象。
13.2 缺点
1、复杂性增加
须要将对象的内部状态和外部状态分离,增加了体系的复杂性。
2、共享对象的线程安全标题
如果多个线程同时访问共享对象,大概会导致线程安全标题。
14. 代理模式
代理模式允许你提供一个代理对象来控制对另一个对象的访问。代理对象通常会在客户端和目的对象之间起到中介的作用,从而可以在不改变目的对象的情况下,增加额外的功能或控制访问。
假设我们有一个文件加载器(FileLoader),它负责加载文件内容。我们可以利用代理模式来实现耽误加载(Lazy Loading),即只有在须要时才加载文件内容。
耽误加载,即只有在须要时才初始化目的对象。
①、界说抽象主题
- public interface IFileLoader
- {
- string LoadFile();
- }
复制代码 ②、界说真实主题
- public class FileLoader : IFileLoader
- {
- private string _filePath;
- public FileLoader(string filePath)
- {
- _filePath = filePath;
- // 模拟文件加载的耗时操作(10 秒)
- Console.WriteLine("文件加载中...");
- Thread.Sleep(10000); // 模拟耗时 10 秒
- }
- public string LoadFile()
- {
- // 模拟读取文件内容
- return $"文件内容:{_filePath}";
- }
- }
复制代码 ③、界说代理
- public class FileLoaderProxy : IFileLoader
- {
- private string _filePath;
- private FileLoader _fileLoader;
- public FileLoaderProxy(string filePath)
- {
- _filePath = filePath;
- }
- public string LoadFile()
- {
- // 权限验证
- if (!CheckAccess())
- {
- throw new UnauthorizedAccessException("无权访问文件!");
- }
- // 日志
记录:方法调用前 - Log("开始加载文件...");
- // 延迟加载:只有在需要时才创建真实对象
- if (_fileLoader == null)
- {
- _fileLoader = new FileLoader(_filePath);
- }
- // 调用真实对象的方法
- string content = _fileLoader.LoadFile();
- // 日志
记录:方法调用后 - Log("文件加载完成。");
- return content;
- }
- private bool CheckAccess()
- {
- // 模拟权限验证
- Console.WriteLine("权限验证中...");
- Thread.Sleep(1000); // 模拟耗时 1 秒
- return true; // 假设权限验证通过
- }
- private void Log(string message)
- {
- // 模拟日志
记录 - Console.WriteLine($"[日志] {DateTime.Now}: {message}");
- }
- }
复制代码 ④、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建代理对象
- IFileLoader fileLoader = new FileLoaderProxy("example.txt");
- try
- {
- // 第一次调用时加载文件
- Console.WriteLine(fileLoader.LoadFile());
- // 第二次调用时直接使用已加载的文件
- Console.WriteLine(fileLoader.LoadFile());
- }
- catch (UnauthorizedAccessException ex)
- {
- Console.WriteLine(ex.Message);
- }
- }
- }
复制代码 14.1 长处
1、控制访问
代理模式可以控制客户端对目的对象的访问,比方耽误加载、权限验证等。
2、增加功能
代理模式可以在不修改目的对象的情况下,为目的对象增加额外的功能,比方日记记录、性能监控 等。
3、解耦
代理模式将客户端与目的对象解耦,客户端只须要与代理对象交互。
14.2 缺点
1、复杂性增加
代理模式引入了额外的类,增加了体系的复杂性。
2、性能开销
代理对象大概会引入额外的性能开销,比方耽误加载的初始化时间。
15. 模板方法模式
模板方法模式是一种举动型操持模式,它界说了一个算法的骨架,并将某些步调耽误到子类中实现。模板方法模式使得子类可以在不改变算法结构的情况下,重新界说算法的某些特定步调。
模板方法模式的核心是界说算法的骨架;抽象方法耽误到子类中实现。
如:你有一个抽象类,界说了一个方法(算法骨架),该方法由多个操纵方法组成,多个操纵方法中有部分是抽象方法,再有一个具体类实现了抽象类,且实现了抽象方法(耽误到子类实现)。以上操纵可以分析你利用了模板方法模式。
假设我们正在开辟一个饮料制作体系,支持多种饮料(如咖啡、茶)。每种饮料的制作过程大致相同,但某些步调的具体实现差别。我们可以利用模板方法模式来实现。
如果倒霉用模板方法模式,则须要创建两个类(制作咖啡、制作茶),但这两个类的制作步调有部分相同,以是会有代码重复;如果相同的逻辑须要修改,则须要在多个类举行重复修改;如果新增一种饮料(如制作热巧克力),则须要重复编写相同的逻辑和代码。
①、界说抽象类
- public abstract class Beverage
- {
- // 模板方法:定义算法的骨架
- public void PrepareBeverage()
- {
- BoilWater();
- Brew();
- PourInCup();
- AddCondiments();
- }
- // 具体步骤:煮沸水
- private void BoilWater()
- {
- Console.WriteLine("煮沸水");
- }
- // 抽象步骤:冲泡
- protected abstract void Brew();
- // 具体步骤:倒入杯子
- private void PourInCup()
- {
- Console.WriteLine("倒入杯子");
- }
- // 抽象步骤:添加调料
- protected abstract void AddCondiments();
- }
复制代码 ②、界说具体类
- // 咖啡
- public class Coffee : Beverage
- {
- protected override void Brew()
- {
- Console.WriteLine("冲泡咖啡");
- }
- protected override void AddCondiments()
- {
- Console.WriteLine("添加糖和牛奶");
- }
- }
复制代码- // 茶
- public class Tea : Beverage
- {
- protected override void Brew()
- {
- Console.WriteLine("冲泡茶叶");
- }
- protected override void AddCondiments()
- {
- Console.WriteLine("添加柠檬");
- }
- }
复制代码 ③、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 制作咖啡
- Beverage coffee = new Coffee();
- Console.WriteLine("制作咖啡:");
- coffee.PrepareBeverage();
- Console.WriteLine();
- // 制作茶
- Beverage tea = new Tea();
- Console.WriteLine("制作茶:");
- tea.PrepareBeverage();
- }
- }
复制代码 15.1 长处
1、复用代码
模板方法模式通过将通用的算法逻辑放在父类中,制止了代码重复。
2、扩展性
子类可以通过实现抽象方法或钩子方法,扩展算法的某些步调。
3、符合开闭原则
算法的骨架在父类中界说,子类可以通过扩展来实现差别的举动,而无需修改父类。
15.2 缺点
1、复杂性增加
每新增一种算法步调的实现,都须要创建一个新的子类。
2、机动性受限
模板方法模式要求算法的步调顺序固定,大概限定了机动性。
16. 命令模式
命令模式是一种举动型操持模式,它将哀求封装为一个对象,从而使你可以用差别的哀求对客户举行参数化,并支持哀求的列队、记录日记、取消操纵等功能。
假设我们正在开辟一个遥控器体系,遥控器可以控制多种装备(如灯、风扇)。我们可以利用命令模式来实现遥控器的按钮功能。
①、界说命令接口
- public interface ICommand
- {
- void Execute();
- }
复制代码 ②、界说吸收者
- // 灯
- public class Light
- {
- public void On()
- {
- Console.WriteLine("灯打开了");
- }
- public void Off()
- {
- Console.WriteLine("灯关闭了");
- }
- }
复制代码- // 风扇
- public class Fan
- {
- public void On()
- {
- Console.WriteLine("风扇打开了");
- }
- public void Off()
- {
- Console.WriteLine("风扇关闭了");
- }
- }
复制代码 ③、界说具体命令
- // 打开灯的命令
- public class LightOnCommand : ICommand
- {
- private Light _light;
- public LightOnCommand(Light light)
- {
- _light = light;
- }
- public void Execute()
- {
- _light.On();
- }
- }
复制代码- // 关闭灯的命令
- public class LightOffCommand : ICommand
- {
- private Light _light;
- public LightOffCommand(Light light)
- {
- _light = light;
- }
- public void Execute()
- {
- _light.Off();
- }
- }
复制代码- // 打开风扇的命令
- public class FanOnCommand : ICommand
- {
- private Fan _fan;
- public FanOnCommand(Fan fan)
- {
- _fan = fan;
- }
- public void Execute()
- {
- _fan.On();
- }
- }
复制代码- // 关闭风扇的命令
- public class FanOffCommand : ICommand
- {
- private Fan _fan;
- public FanOffCommand(Fan fan)
- {
- _fan = fan;
- }
- public void Execute()
- {
- _fan.Off();
- }
- }
复制代码 ④、界说调用者
- public class RemoteControl
- {
- private ICommand _command;
- public void SetCommand(ICommand command)
- {
- _command = command;
- }
- public void PressButton()
- {
- _command.Execute();
- }
- }
复制代码 ⑤、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建接收者
- Light light = new Light();
- Fan fan = new Fan();
- // 创建命令对象
- ICommand lightOn = new LightOnCommand(light);
- ICommand lightOff = new LightOffCommand(light);
- ICommand fanOn = new FanOnCommand(fan);
- ICommand fanOff = new FanOffCommand(fan);
- // 创建调用者
- RemoteControl remote = new RemoteControl();
- // 打开灯
- remote.SetCommand(lightOn);
- remote.PressButton();
- // 关闭灯
- remote.SetCommand(lightOff);
- remote.PressButton();
- // 打开风扇
- remote.SetCommand(fanOn);
- remote.PressButton();
- // 关闭风扇
- remote.SetCommand(fanOff);
- remote.PressButton();
- }
- }
复制代码 16.1 长处
1、解耦
命令模式将哀求的发送者(客户端)与哀求的吸收者(实行者)解耦,客户端不须要知道哀求的具体实行者。
2、扩展性
可以轻松地扩展新的命令,而无需修改现有代码。
3、支持取消操纵
可以通过在命令对象中添加取消方法来实现取消操纵。
4、支持队列和日记
可以将命令对象存储在队列中,大概记录命令的实行日记。
16.2 缺点
1、复杂性增加
每新增一个命令,都须要创建一个新的命令类,导致类的数量增加。
2、性能开销
命令对象大概会引入额外的性能开销,比方命令的创建和实行。
17. 迭代器模式
迭代器模式是一种举动型操持模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而又不袒露其内部的表现。迭代器模式将遍历聚合对象的责任分离出来,使得聚合对象和遍历算法可以独立变革。
假设我们有一个聚集类(MyCollection),它存储了一组整数。我们可以利用迭代器模式来遍历这个聚集。
如果倒霉用迭代器,一旦聚合内部结构发生变革(如从数组改为链表),客户端须要修改遍历代码。如果新增一种遍历方式(如反向遍历、深度优先遍历),须要在客户端中重复编写遍历逻辑。固然,如果聚合对象结构简单(如数组大概列表),而且不会发生变革,那么可以直接利用 for 大概 foreach 遍历。如果遍历逻辑简单(如顺序遍历),且不须要支持多种遍历方法,那么也是可以直接编写遍历代码的。且 C# 的 foreach 已经是内置了遍历支持了,因此也可以不须要手动实现迭代器模式。
①、界说迭代器接口
- public interface IIterator
- {
- bool HasNext();
- int Next();
- }
复制代码 ②、界说具体迭代器
- public class MyIterator : IIterator
- {
- private int[] _collection;
- private int _position = 0;
- public MyIterator(int[] collection)
- {
- _collection = collection;
- }
- public bool HasNext()
- {
- return _position < _collection.Length;
- }
- public int Next()
- {
- return _collection[_position++];
- }
- }
复制代码 ③、界说聚合接口
- public interface IAggregate
- {
- IIterator CreateIterator();
- }
复制代码 ④、界说具体聚合
- public class MyCollection : IAggregate
- {
- private int[] _collection;
- public MyCollection(int[] collection)
- {
- _collection = collection;
- }
- public IIterator CreateIterator()
- {
- return new MyIterator(_collection);
- }
- }
复制代码 ⑤、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建聚合对象
- int[] numbers = { 1, 2, 3, 4, 5 };
- MyCollection collection = new MyCollection(numbers);
- // 创建迭代器
- IIterator iterator = collection.CreateIterator();
- // 遍历聚合对象
- while (iterator.HasNext())
- {
- Console.WriteLine(iterator.Next());
- }
- }
- }
复制代码 17.1 长处
1、解耦
迭代器模式将遍历聚合对象的责任分离出来,使得聚合对象和遍历算法可以独立变革。
2、支持多种遍历方式
迭代器模式可以支持多种遍历方式,比方正向遍历、反向遍历、深度优先遍历等。
3、简化聚合接口
聚合对象只须要提供一个创建迭代器的接口,而不须要袒露其内部结构。
17.2 缺点
1、复杂性增加
每新增一种遍历方式,都须要创建一个新的迭代器类,导致类的数量增加。
2、性能开销
迭代器对象大概会引入额外的性能开销,比方迭代器的创建和管理。
18. 观察者模式
观察者模式是一种举动型操持模式,它界说了对象之间的一对多依赖关系,使适当一个对象的状态发生改变时,全部依赖于它的对象都会自动收到关照并更新。观察者模式也被称为发布—订阅模式(Publish-Subscribe Pattern)。
假设我们有一个气候站(WeatherStation),它可以发布气候数据(如温度、湿度)。我们可以利用观察者模式来实现气候数据的发布和订阅。
固然,如果直接利用变乱,也可以算是利用了观察者模式,因为变乱机制是观察者模式的一种实现方式。变乱的核心头脑就是发布—订阅,即一个对象(发布者)发布变乱,其他对象(订阅者)订阅并相应这些变乱。
①、界说观察者接口
- public interface IObserver
- {
- void Update(float temperature, float humidity);
- }
复制代码 ②、界说主题接口
- public interface ISubject
- {
- void RegisterObserver(IObserver observer);
- void RemoveObserver(IObserver observer);
- void NotifyObservers();
- }
复制代码 ③、界说具体主题
- public class WeatherStation : ISubject
- {
- private List<IObserver> _observers = new List<IObserver>();
- private float _temperature;
- private float _humidity;
- public void RegisterObserver(IObserver observer)
- {
- _observers.Add(observer);
- }
- public void RemoveObserver(IObserver observer)
- {
- _observers.Remove(observer);
- }
- public void NotifyObservers()
- {
- foreach (var observer in _observers)
- {
- observer.Update(_temperature, _humidity);
- }
- }
- public void SetMeasurements(float temperature, float humidity)
- {
- _temperature = temperature;
- _humidity = humidity;
- NotifyObservers();
- }
- }
复制代码 ④、 界说具体观察者
- // 手机显示
- public class PhoneDisplay : IObserver
- {
- private float _temperature;
- private float _humidity;
- public void Update(float temperature, float humidity)
- {
- _temperature = temperature;
- _humidity = humidity;
- Display();
- }
- private void Display()
- {
- Console.WriteLine($"手机显示:温度 = {_temperature}°C,湿度 = {_humidity}%");
- }
- }
复制代码- // 电视显示
- public class TVDisplay : IObserver
- {
- private float _temperature;
- private float _humidity;
- public void Update(float temperature, float humidity)
- {
- _temperature = temperature;
- _humidity = humidity;
- Display();
- }
- private void Display()
- {
- Console.WriteLine($"电视显示:温度 = {_temperature}°C,湿度 = {_humidity}%");
- }
- }
复制代码 ⑤、 客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建主题对象
- WeatherStation weatherStation = new WeatherStation();
- // 创建观察者对象
- PhoneDisplay phoneDisplay = new PhoneDisplay();
- TVDisplay tvDisplay = new TVDisplay();
- // 注册观察者
- weatherStation.RegisterObserver(phoneDisplay);
- weatherStation.RegisterObserver(tvDisplay);
- // 更新天气数据
- weatherStation.SetMeasurements(25.0f, 60.0f);
- // 移除一个观察者
- weatherStation.RemoveObserver(tvDisplay);
- // 再次更新天气数据
- weatherStation.SetMeasurements(30.0f, 50.0f);
- }
- }
复制代码 18.1 长处
1、解耦
观察者模式将主题对象与观察者对象解耦,主题对象不须要知道观察者对象的具体实现。
2、支持动态添加和删除观察者
观察者模式允许在运行时动态添加和删除观察者。
3、符合开闭原则
新增观察者时,不须要修改主题对象的代码。
18.2 缺点
1、关照顺序不确定
观察者模式没有界说观察者吸收关照的顺序,大概会导致不测的举动。
2、性能标题
如果观察者数量非常多,关照全部观察者大概会导致性能标题。
19. 中介者模式
中介者模式通过引入一个中介者对象来封装一组对象之间的交互,从而减少对象之间的直接依赖,使得对象之间的耦合度低落。中介者模式的核心头脑是将对象之间的复杂交互会合到一个中介者对象中,而不是让对象直接相互通讯。
假设我们有一个聊天室体系,多个用户(User)可以在聊天室中发送消息。我们可以利用中介者模式来实现用户之间的消息转达。
固然,如果两个对象之间通讯(交互),大概交互的逻辑比力简单,这时间引入中介者模式会增加额外的类和复杂性。
①、界说中介者接口
- public interface IChatRoomMediator
- {
- void SendMessage(string message, User user);
- void AddUser(User user);
- }
复制代码 ②、界说具体中介者
- public class ChatRoom : IChatRoomMediator
- {
- private List<User> _users = new List<User>();
- public void AddUser(User user)
- {
- _users.Add(user);
- }
- public void SendMessage(string message, User user)
- {
- foreach (var u in _users)
- {
- // 不将消息发送给自己
- if (u != user)
- {
- u.Receive(message);
- }
- }
- }
- }
复制代码 ③、界说同事类接口
- public abstract class User
- {
- protected IChatRoomMediator _mediator;
- public string Name { get; }
- public User(string name, IChatRoomMediator mediator)
- {
- Name = name;
- _mediator = mediator;
- }
- public abstract void Send(string message);
- public abstract void Receive(string message);
- }
复制代码 ④、界说具体同事类
- public class ChatUser : User
- {
- public ChatUser(string name, IChatRoomMediator mediator) : base(name, mediator)
- {
- }
- public override void Send(string message)
- {
- Console.WriteLine($"{Name} 发送消息:{message}");
- _mediator.SendMessage(message, this);
- }
- public override void Receive(string message)
- {
- Console.WriteLine($"{Name} 收到消息:{message}");
- }
- }
复制代码 ⑤、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建中介者
- IChatRoomMediator chatRoom = new ChatRoom();
- // 创建用户
- User alice = new ChatUser("Alice", chatRoom);
- User bob = new ChatUser("Bob", chatRoom);
- User charlie = new ChatUser("Charlie", chatRoom);
- // 将用户添加到聊天室
- chatRoom.AddUser(alice);
- chatRoom.AddUser(bob);
- chatRoom.AddUser(charlie);
- // 用户发送消息
- alice.Send("大家好!");
- bob.Send("你好,Alice!");
- charlie.Send("你们在聊什么?");
- }
- }
复制代码 19.1 长处
1、解耦
中介者模式减少了对象之间的直接依赖,使得对象之间的耦合度低落。
2、会合控制
中介者模式将对象之间的交互会合到一个中介者对象中,使得交互逻辑更加清楚和易于维护。
3、简化对象职责
对象只须要与中介者交互,而不须要知道其他对象的存在。
19.2 缺点
1、中介者对象大概变得复杂
如果对象之间的交互逻辑非常复杂,中介者对象大概会变得痴肥和难以维护。
2、性能标题
中介者对象须要处置惩罚全部对象之间的交互,大概会导致性能标题。
20. 状态模式
状态模式是一种举动型操持模式,它允许一个对象在其内部状态改变时改变其举动。状态模式将对象的举动封装在差别的状态类中,使得对象在差别状态下可以有差别的举动体现。
利用场景:
1、对象的举动依赖于其状态
比方,电灯的状态切换、订单的状态流转。
2、须要制止大量的条件判定语句
比方,复杂的条件逻辑可以通过状态模式来简化。
3、状态转换逻辑复杂
比方,有限状态机(FSM)中的状态转换。
假设我们有一个电灯(Light),它有两种状态:打开(On)和关闭(Off)。我们可以利用状态模式来实现电灯的状态切换。
如果倒霉用状态模式,电灯类中包罗了状态相干的举动逻辑,随着状态的增加,条件判定语句会越来越多,导致代码痴肥;状态相干的举动与电灯类精密耦合,状态的变革会直接影响到电灯类的代码;如果新增一种状态(比方“闪灼”状态),须要修改电灯类的代码,违反了开闭原则;大量的条件判定语句会低落代码的可读性和可维护性。
固然,如果状态逻辑简单、状态数量少等条件下,大概不须要利用状态模式。
①、界说状态接口
- public interface ILightState
- {
- void Handle(Light light);
- }
复制代码 ②、界说具体状态
- // 打开状态
- public class OnState : ILightState
- {
- public void Handle(Light light)
- {
- Console.WriteLine("电灯已经打开");
- light.SetState(new OffState());
- }
- }
复制代码- // 关闭状态
- public class OffState : ILightState
- {
- public void Handle(Light light)
- {
- Console.WriteLine("电灯已经关闭");
- light.SetState(new OnState());
- }
- }
复制代码 ③、界说上下文
- public class Light
- {
- private ILightState _state;
- public Light(ILightState state)
- {
- _state = state;
- }
- public void SetState(ILightState state)
- {
- _state = state;
- }
- public void PressSwitch()
- {
- _state.Handle(this);
- }
- }
复制代码 ④、客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- // 创建电灯对象,初始状态为关闭
- Light light = new Light(new OffState());
- // 按下开关
- light.PressSwitch(); // 打开电灯
- light.PressSwitch(); // 关闭电灯
- light.PressSwitch(); // 打开电灯
- }
- }
复制代码 20.1 长处
1、解耦
状态模式将状态相干的举动封装在差别的状态类中,制止了大量的条件判定语句。
2、易于扩展
新增状态时,只需添加新的状态类,而无需修改现有代码。
3、符合开闭原则
对扩展开放,对修改关闭。
20.2 缺点
1、复杂性增加
每新增一个状态,都须要创建一个新的状态类,导致类的数量增加。
2、状态转换逻辑分散
状态转换逻辑分散在各个状态类中,大概会导致状态转换逻辑难以维护。
21. 战略模式
战略模式是一种举动操持模式,它允许在运行时选择算法的举动。战略模式通过界说一系列算法或战略,并将它们封装在独立的类中,使得它们可以相互更换。如许,客户端代码可以根据须要选择差别的战略,而不须要修改其结构。
以下是一个简单的战略模式示例,模仿差别的付出战略:
- using System;
- // 策略接口
- public interface IPaymentStrategy
- {
- void Pay(decimal amount);
- }
- // 具体策略类:信用卡支付
- public class CreditCardPayment : IPaymentStrategy
- {
- public void Pay(decimal amount)
- {
- Console.WriteLine($"Paid {amount} via Credit Card.");
- }
- }
- // 具体策略类:支付宝支付
- public class AlipayPayment : IPaymentStrategy
- {
- public void Pay(decimal amount)
- {
- Console.WriteLine($"Paid {amount} via Alipay.");
- }
- }
- // 具体策略类:微信支付
- public class WeChatPayment : IPaymentStrategy
- {
- public void Pay(decimal amount)
- {
- Console.WriteLine($"Paid {amount} via WeChat.");
- }
- }
- // 上下文类
- public class PaymentContext
- {
- private IPaymentStrategy _strategy;
- public PaymentContext(IPaymentStrategy strategy)
- {
- _strategy = strategy;
- }
- public void SetStrategy(IPaymentStrategy strategy)
- {
- _strategy = strategy;
- }
- public void ExecutePayment(decimal amount)
- {
- _strategy.Pay(amount);
- }
- }
- // 客户端代码
- class Program
- {
- static void Main(string[] args)
- {
- var context = new PaymentContext(new CreditCardPayment());
- context.ExecutePayment(100.00m); // 使用信用卡支付
- context.SetStrategy(new AlipayPayment());
- context.ExecutePayment(200.00m); // 切换到支付宝支付
- context.SetStrategy(new WeChatPayment());
- context.ExecutePayment(300.00m); // 切换到微信支付
- }
- }
复制代码 21.1 长处
1、开闭原则:
可以在不修改客户端代码的情况下引入新的战略。 扩展性强,易于维护。
2、制止条件语句:
通过战略模式可以制止利用复杂的条件语句(如 if-else 或 switch )来选择算法。
3、进步代码复用性:
将算法封装在独立的类中,可以在差别的上下文中复用。
4、机动性:
可以在运行时动态切换战略,顺应差别的需求。
21.2 缺点
1、类的数量增加:
每个战略都须要一个独立的类,大概会导致类的数量增多。
2、客户端须要相识战略:
客户端须要知道差别战略的区别,以便选择合适的战略。
3、太过操持:
如果算法非常简单或数量很少,利用战略模式大概会显得过于复杂。
22. 责任链模式
责任链模式是一种举动操持模式,它允很多个对象偶然机处置惩罚哀求,从而制止哀求的发送者与吸收者之间的耦合。责任链模式将这些对象连成一条链,并沿着这条链转达哀求,直到有对象处置惩罚它为止。
以下是一个简单的责任链模式示例,模仿一个多级审批流程:
22.1 长处
1、解耦哀求发送者和处置惩罚者:
哀求发送者不须要知道具体由哪个处置惩罚器处置惩罚哀求,只须要将哀求发送到链中。
2、动态调解职责:
可以在运行时动态地调解处置惩罚器链的顺序或职责。
3、符合单一职责原则:
每个处置惩罚器只负责处置惩罚本身能处置惩罚的哀求,职责单一。
4、符合开闭原则:
新增处置惩罚器时不须要修改现有代码,只需扩展新的处置惩罚器。
22.2 缺点
1、哀求大概未被处置惩罚:
如果链中没有处置惩罚器能够处置惩罚哀求,哀求大概会丢失或未被处置惩罚。
2、性能标题:
如果链过长,大概会导致哀求转达的开销增加。
3、调试困难:
由于哀求的处置惩罚是动态的,调试时大概难以追踪哀求的处置惩罚过程。
23. 访问者模式
访问者模式是一种举动操持模式,允许你将算法与对象结构分离。通过这种方式,你可以在不修改对象结构的情况下,向对象结构中的元素添加新的操纵。
假设我们有一个文档处置惩罚体系,文档中包罗差别范例的元素(如文本、图片、表格等),我们须要对这些元素实行差别的操纵(如导出为PDF、拼写查抄等)。
①、界说元素接口和具体元素
- // 文档中的每个元素(如文本、图片、表格)都需要实现一个 Accept 方法,接受访问者。
- // 元素接口
- public interface IDocumentElement
- {
- void Accept(IDocumentVisitor visitor);
- }
- // 具体元素:文本
- public class TextElement : IDocumentElement
- {
- public string Content { get; set; }
- public TextElement(string content)
- {
- Content = content;
- }
- public void Accept(IDocumentVisitor visitor)
- {
- visitor.Visit(this);
- }
- }
- // 具体元素:图片
- public class ImageElement : IDocumentElement
- {
- public string FilePath { get; set; }
- public ImageElement(string filePath)
- {
- FilePath = filePath;
- }
- public void Accept(IDocumentVisitor visitor)
- {
- visitor.Visit(this);
- }
- }
- // 具体元素:表格
- public class TableElement : IDocumentElement
- {
- public int Rows { get; set; }
- public int Columns { get; set; }
- public TableElement(int rows, int columns)
- {
- Rows = rows;
- Columns = columns;
- }
- public void Accept(IDocumentVisitor visitor)
- {
- visitor.Visit(this);
- }
- }
复制代码 ②、界说访问者接口和具体访问者
- // 访问者接口定义了针对每种元素的操作,具体访问者实现这些操作。
- // 访问者接口
- public interface IDocumentVisitor
- {
- void Visit(TextElement text);
- void Visit(ImageElement image);
- void Visit(TableElement table);
- }
- // 具体访问者:导出为PDF
- public class PdfExportVisitor : IDocumentVisitor
- {
- public void Visit(TextElement text)
- {
- Console.WriteLine($"Exporting text to PDF: {text.Content}");
- }
- public void Visit(ImageElement image)
- {
- Console.WriteLine($"Exporting image to PDF: {image.FilePath}");
- }
- public void Visit(TableElement table)
- {
- Console.WriteLine($"Exporting table to PDF: {table.Rows}x{table.Columns}");
- }
- }
- // 具体访问者:拼写检查
- public class SpellCheckVisitor : IDocumentVisitor
- {
- public void Visit(TextElement text)
- {
- Console.WriteLine($"Spell checking text: {text.Content}");
- }
- public void Visit(ImageElement image)
- {
- Console.WriteLine($"Spell checking image: {image.FilePath} (no text to check)");
- }
- public void Visit(TableElement table)
- {
- Console.WriteLine($"Spell checking table: {table.Rows}x{table.Columns} (no text to check)");
- }
- }
复制代码 ③、界说对象结构
- // 对象结构(如文档)包含一组元素,并提供方法让访问者访问这些元素。
- public class Document
- {
- private List<IDocumentElement> _elements = new List<IDocumentElement>();
- public void AddElement(IDocumentElement element)
- {
- _elements.Add(element);
- }
- public void Accept(IDocumentVisitor visitor)
- {
- foreach (var element in _elements)
- {
- element.Accept(visitor);
- }
- }
- }
复制代码 ④、客户端代码
- // 客户端创建文档对象,添加元素,并使用不同的访问者执行操作。
- public class Client
- {
- public static void Main(string[] args)
- {
- // 创建文档
- Document document = new Document();
- document.AddElement(new TextElement("Hello, World!"));
- document.AddElement(new ImageElement("photo.jpg"));
- document.AddElement(new TableElement(3, 5));
- // 创建访问者
- IDocumentVisitor pdfExportVisitor = new PdfExportVisitor();
- IDocumentVisitor spellCheckVisitor = new SpellCheckVisitor();
- // 执行操作
- Console.WriteLine("Exporting document to PDF:");
- document.Accept(pdfExportVisitor);
- Console.WriteLine("\nPerforming spell check:");
- document.Accept(spellCheckVisitor);
- }
- }
复制代码
23.1 长处
1、开闭原则:
可以在不修改现有对象结构的情况下添加新的操纵。
2、单一职责原则:
将相干的操纵会合在一个访问者中,使得职责更加清楚。
3、机动性:
可以在运行时选择差别的访问者来实行差别的操纵。
23.2 缺点
1、增加复杂性:
访问者模式增加了体系的复杂性,特殊是在对象结构常常变革的情况下。
2、粉碎封装:
访问者模式须要袒露元素的内部状态,大概会粉碎封装性。
24. 备忘录模式
备忘录模式是一种举动操持模式,它允许在不粉碎封装性的前提下,捕捉并外部化对象的内部状态,以便在须要时可以将对象规复到之前的状态。备忘录模式通常用于实现取消(Undo)或规复(Redo)功能。
以下是一个简单的C#实现示例,模仿文本编辑器的取消功能:
①、备忘录(存储文本编辑器的状态)
- public class TextMemento
- {
- public string Text { get; }
- public TextMemento(string text)
- {
- Text = text;
- }
- }
复制代码 ②、原发器(负责创建备忘录和规复功能)
- public class TextEditor
- {
- private string _text;
- public TextEditor(string text)
- {
- _text = text;
- }
- public void Append(string newText)
- {
- _text += newText;
- }
- public TextMemento Save()
- {
- return new TextMemento(_text);
- }
- public void Restore(TextMemento memento)
- {
- _text = memento.Text;
- }
- public void Print()
- {
- Console.WriteLine($"Current Text: {_text}");
- }
- }
复制代码 ③、管理者(负责保存和管理备忘录)
- public class History
- {
- private Stack<TextMemento> _mementos = new Stack<TextMemento>();
- public void Save(TextMemento memento)
- {
- _mementos.Push(memento);
- }
- public TextMemento Undo()
- {
- if (_mementos.Count > 0)
- {
- return _mementos.Pop();
- }
- return null;
- }
- }
复制代码 ④、客户端代码
- public class Client
- {
- public static void Main(string[] args)
- {
- TextEditor editor = new TextEditor("Hello");
- History history = new History();
- // 编辑文本并保存状态
- editor.Print();
- history.Save(editor.Save());
- editor.Append(", World!");
- editor.Print();
- history.Save(editor.Save());
- editor.Append(" How are you?");
- editor.Print();
- // 撤销操作
- Console.WriteLine("\nUndoing last change...");
- editor.Restore(history.Undo());
- editor.Print();
- Console.WriteLine("\nUndoing last change...");
- editor.Restore(history.Undo());
- editor.Print();
- }
- }
复制代码 24.1 长处
1、封装性:
备忘录模式将对象的状态封装在备忘录中,外部对象无法直接访问或修改状态。
2、简化原发器:
原发器不须要管理状态的存储和规复逻辑,这些职责由管理者承担。
3、支持取消/规复功能:
备忘录模式非常得当实现取消(Undo)和规复(Redo)功能。
24.2 缺点
1、资源消耗:
如果对象的状态非常大或频仍保存,备忘录模式大概会占用大量内存。
2、性能开销:
频仍创建和规复备忘录大概会影响性能。
25. 表明器模式
表明器模式是一种举动操持模式,它用于界说语言的文法规则,并提供一个表明器来表明语言中的句子。表明器模式通常用于处置惩罚类似编程语言、查询语言或表达式剖析的场景。
以下是一个简单的C#实现示例,模仿一个简单的布尔表达式表明器:
①、抽象表达式(界说表明操纵的接口)
- public interface IExpression
- {
- bool Interpret(Dictionary<string, bool> context);
- }
复制代码 ②、闭幕符表达式(实现与文法中的闭幕符相干的表明操纵)
- public class VariableExpression : IExpression
- {
- private string _variableName;
- public VariableExpression(string variableName)
- {
- _variableName = variableName;
- }
- public bool Interpret(Dictionary<string, bool> context)
- {
- return context[_variableName];
- }
- }
复制代码 ③、非闭幕符表达式(实现与文法中的非闭幕符相干的表明操纵)
- public class AndExpression : IExpression
- {
- private IExpression _left;
- private IExpression _right;
- public AndExpression(IExpression left, IExpression right)
- {
- _left = left;
- _right = right;
- }
- public bool Interpret(Dictionary<string, bool> context)
- {
- return _left.Interpret(context) && _right.Interpret(context);
- }
- }
- public class OrExpression : IExpression
- {
- private IExpression _left;
- private IExpression _right;
- public OrExpression(IExpression left, IExpression right)
- {
- _left = left;
- _right = right;
- }
- public bool Interpret(Dictionary<string, bool> context)
- {
- return _left.Interpret(context) || _right.Interpret(context);
- }
- }
- public class NotExpression : IExpression
- {
- private IExpression _expression;
- public NotExpression(IExpression expression)
- {
- _expression = expression;
- }
- public bool Interpret(Dictionary<string, bool> context)
- {
- return !_expression.Interpret(context);
- }
- }
复制代码 ④、客户端代码
- public class Client
- {
- public static void Main(string[] args)
- {
- // 定义上下文
- var context = new Dictionary<string, bool>
- {
- { "A", true },
- { "B", false },
- { "C", true }
- };
- // 构建抽象语法树
- var expression = new AndExpression(
- new VariableExpression("A"),
- new OrExpression(
- new VariableExpression("B"),
- new NotExpression(new VariableExpression("C"))
- )
- );
- // 解释表达式
- bool result = expression.Interpret(context);
- Console.WriteLine($"Result: {result}");
- }
- }
复制代码 25.1 长处
1、易于扩展:
可以轻松添加新的表达式范例,只需实现新的闭幕符或非闭幕符表达式。
2、符合单一职责原则:
每个表达式类只负责本身的表明逻辑。
3、机动性强:
可以动态地改变表明逻辑,通过组合差别的表达式。
25.2 缺点
1、复杂度高:
对于复杂的文法,表明器模式大概会导致类的数量急剧增加。
2、性能标题:
表明器模式通常利用递归调用,大概会导致性能标题。
3、难以维护:
如果文法规则频仍变革,维护表明器大概会变得困难。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|