概述
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的代码设计经验的总结
本文是《C#设计模式》书籍的学习笔记
面向对象设计原则
单一职责原则 | 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中 |
开闭原则 | 对扩展开放,对修改关闭。在不修改原有代码的基础上进行扩展 |
里氏替换原则 | 系统中引用父类对象的地方都可以使用子类对象进行代替 |
依赖倒转原则 | 针对抽象编程,不要针对实现编程 |
迪米特法则 | 尽量少地与其他软件实体发生相互作用 |
合成复用原则 | 在代码复用时,尽量使用组合/聚合关系,少用继承 |
接口隔离原则 | 客户端不应该依赖那些不需要的接口 |
目的:
1、降低对象之间的耦合度
2、增加程序的可复用性、可扩展性和可维护性
设计模式
创建型模式
Creational Pattern
目标:关注对象的创建过程,将对象的创建和对象的使用分离,让用户在使用时无须关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展。
包含5种GoF创建型模式,一种非GoF创建型模式(简单工厂模式):
模式 | 类型 | 处理哪种问题 | 学习难度 | 使用频率 |
单例模式 (Singleton) | 对象创建型模式 | 确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例 | ⭐ | ⭐⭐⭐⭐ |
简单工厂模式 (Simple Factory) | 类创建型模式 | 根据传入参数的不同返回不同的实例 | ⭐⭐ | ⭐⭐⭐ |
工厂方法模式 (Factory Method) | 类创建型模式 | 每一类产品对应一个工厂,每个工厂只生产一种产品 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
抽象工厂模式 (Abstract Factory) | 对象创建型模式 | 每一个抽象工厂可以生产一个产品族,一个产品族包含多个产品等级结构 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
原型模式 (Prototype) | 对象创建型模式 | 复制一个已有对象来获取更多相同或者相似的对象 | ⭐⭐⭐ | ⭐⭐⭐ |
建造者模式 (Builder) | 对象创建型模式 | 创建一个包含多个组成部件的复杂对象,使用相同的构建过程构建不同的产品 | ⭐⭐⭐⭐ | ⭐⭐ |
单例模式
定义:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例
实现要点
1、包含一个静态私有成员变量,用于存储唯一实例。
2、包含一个私有构造函数,确保用户无法通过new关键字直接实例化它。
3、包含一个静态公有的工厂方法,作为一个全局访问点,返回唯一实例。
饿汉式单例
在定义静态变量的时候实例单例类,因此在类加载时单例对象就已创建。
private static SingletonPattern instance = new SingletonPattern();
private SingletonPattern() { }
public static SingletonPattern Instance()
{
return instance;
}
懒汉式单例
//第一次被引用时将自己实例化
private static SingletonPattern instance = null;
private SingletonPattern() { }
//创建一个静态只读辅助对象
private static readonly object syncRoot = new object();
public static SingletonPattern GetInstance()
{
//双重检查锁定(Double-Check Locking) 双重判断机制
//第一重判断,先判断实例是否存在,不存在再加锁处理
if (instance == null)
{
//加锁的程序在某一时刻只允许一个线程访问
lock (syncRoot)
{
//第二重判断
if (instance == null)
{
instance = new SingletonPattern();
}
}
}
return instance;
}
饿汉式单例类和懒汉式单例类比较
实例化时机 | 优点 | 缺点 | |
饿汉式单例类 | 在类被加载时创建唯一实例 | 1、无须考虑多个线程同时访问的问题,可以确保实例的唯一性 2、从调用速度和反应时间角度来看,由于单例对象一开始就得以创建,因此要优于懒汉式单例。 | 由于在类加载时该对象就需要创建 1、因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例 2、加载时间可能会比较长 |
懒汉式单例类 | 在第一次调用静态工厂方法时创建唯一实例 | 1、无须一直占用系统资源,实现了延迟加载 | 1、需要处理多个线程访问的问题 2、因为使用双重检查锁定机制,将导致系统性能受到一定的影响 |
优缺点
优点 | 1、方便对实例个数进行控制,节约系统资源,提高系统性能 2、缺少抽象层,难以扩展 |
缺点 | 1、单例类职责过重,一定程度上违背了单一职责原则 |
适用场景
1、系统只需要一个实例对象
2、只允许使用一个公共访问点
3、解决实体对象个数过多的问题
工厂模式
简单工厂模式
定义
定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。注:由于在工厂类中用于创建产品实例的方法通常是静态方法,所以又被称为静态工厂方法(Static Factory Pattern)。
模式描述
1、将不同产品对象的相关代码封装到不同的类中,成为具体抽象类。
2、将具体抽象类的公共代码进行提取后封装在一个抽象产品类中,每一个具体抽象类都继承该抽象产品类。
3、提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法(通常是静态方法),根据所传入参数的不同创建不同的具体产品对象。
4、客户只需要调用工厂类的工厂方法并传入相应的参数即可得到一个具体产品对象。
角色组成
包含以下3个角色:
(1)Product(抽象产品角色):作为具体产品类的公共父类
(2)ConcreteProduct(具体产品角色)
(3)Factory(工厂角色):提供静态工厂方法,根据传入参数的不同返回不同的实例,返回类型是抽象产品类
代码示例
public abstract class Drink
{
public abstract void MakeDrinks();
}
//柠檬水
public class Lemonade: Drink
{
public override void MakeDrinks()
{
Console.WriteLine("制作一瓶柠檬水!");
}
}
//橙汁
public class OrangeJuice: Drink
{
public override void MakeDrinks()
{
Console.WriteLine("制作一瓶橙汁!");
}
}
//冷饮店
public class ColdStore
{
public static Drink BuyDrink(string drinkName)
{
switch (drinkName)
{
case "Lemonade":
return new Lemonade();
case "OrangeJuice":
return new OrangeJuice();
default:
return null;
}
}
}
Drink drink;
drink = ColdStore.BuyDrink("OrangeJuice");
drink.MakeDrinks();
优缺点
优点:将对象的创建和使用分离,使得系统更加符合单一职责原则,有利于对功能的复用和系统的维护
缺点:如果增加一个新的具体类,就需要修改工厂类的创建代码,不符合开闭原则
工厂方法模式
定义
简单工厂模式的延伸,不再提供一个公共的工厂类来统一负责所有产品的创建,而是将具体的创建过程交给专门的工厂子类去完成。 针对不同的产品提供不同的工厂。又称为虚拟构造器模式或多态工厂模式
角色组成
(1)Product(抽象产品角色)
(2)ConcreteProduct(具体产品角色)
(3)Factory(抽象工厂角色)
(4)ConcreteFactory(具体工厂角色)
代码示例
public interface IInstrument
{
void Play();
}
public interface IMusicFactory
{
IInstrument CreateInstrument();
}
public class Piano : IInstrument
{
public void Play()
{
Console.WriteLine("钢琴演奏中...");
}
}
public class PianoFactory : IMusicFactory
{
public IInstrument CreateInstrument()
{
var obj = new Piano();
return obj;
}
}
public class Guitar : IInstrument
{
public void Play()
{
Console.WriteLine("吉他演奏中...");
}
}
public class GuitarFactory : IMusicFactory
{
public IInstrument CreateInstrument()
{
var obj = new Guitar();
return obj;
}
}
public class Drum : IInstrument
{
public void Play()
{
Console.WriteLine("爵士鼓演奏中...");
}
}
public class DrumFactory : IMusicFactory
{
public IInstrument CreateInstrument()
{
var obj = new Drum();
return obj;
}
}
优缺点
优点:新增产品时,无需修改原有代码,符合开闭原则。
缺点:新增一个产品类时,需要同时创建与之对应的具体工厂类,系统中类的个数将成对增加,增加了系统的复杂度。因为有更多的类需要编译和运行,会给系统带来一些额外的开销。
抽象工厂模式
定义
负责创建一族产品
产品族:同一个工厂生产的,位于不同产品等级结构中的一组产品
抽象工厂模式与工厂方法模式最大的区别在于:工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构。又称为工具模式,是一种对象创建型模式
角色组成
(1)Product(抽象产品角色)
(2)ConcreteProduct(具体产品角色)
(3)AbstractFactory(抽象工厂角色):声明了一组用于创建一族产品的方法,每一个方法对应一种产品
(4)ConcreteFactory(具体工厂角色)
代码示例
public interface TV
{
public void PlayMovies();
}
public class SAMSUNGTV : TV
{
public void PlayMovies()
{
Console.WriteLine("三星电视播放电影...");
}
}
public class TCLTV : TV
{
public void PlayMovies()
{
Console.WriteLine("TCL电视播放电影...");
}
}
public class HUAWEITV : TV
{
public void PlayMovies()
{
Console.WriteLine("华为电视播放电影...");
}
}
public interface WashingMachine
{
public void WashClothes();
}
public class SAMSUNGWashingMachine : WashingMachine
{
public void WashClothes()
{
Console.WriteLine("三星洗衣机洗衣服中...");
}
}
public class TCLWashingMachine : WashingMachine
{
public void WashClothes()
{
Console.WriteLine("TCL洗衣机洗衣服中...");
}
}
public class HUAWEIWashingMachine : WashingMachine
{
public void WashClothes()
{
Console.WriteLine("华为洗衣机洗衣服中...");
}
}
public interface ElectricFactory
{
public TV CreateTV();
public WashingMachine CreateWashing();
}
public class SAMSUNGFactory : ElectricFactory
{
public TV CreateTV()
{
var tv = new SAMSUNGTV();
return tv;
}
public WashingMachine CreateWashing()
{
var wash = new SAMSUNGWashingMachine();
return wash;
}
}
public class TCLFactory : ElectricFactory
{
public TV CreateTV()
{
var tv = new TCLTV();
return tv;
}
public WashingMachine CreateWashing()
{
var wash = new TCLWashingMachine();
return wash;
}
}
public class HUAWEIFactory : ElectricFactory
{
public TV CreateTV()
{
var tv = new HUAWEITV();
return tv;
}
public WashingMachine CreateWashing()
{
var wash = new HUAWEIWashingMachine();
return wash;
}
}
//抽象工厂类
abstract class SkinFactory
{
public abstract Button CreateButton();//创建按钮
public abstract TextField CreateTextField();//创建文本框
public abstract ComboBox CreateComboBox();//创建组合框
}
//按钮类:抽象产品类
abstract class Button
{
public abstract void Display();
}
//文本框类:抽象产品类
abstract class TextField
{
public abstract void Display();
}
//组合框类:抽象产品类
abstract class ComboBox
{
public abstract void Display();
}
//春天按钮:具体产品类
class SpringButton : Button
{
public override void Display()
{
Console.WriteLine("绘制一个春天风格按钮!");
}
}
//夏天按钮:具体产品类
class SummerButton : Button
{
public override void Display()
{
Console.WriteLine("绘制一个夏天风格按钮!");
}
}
//春天文本框:具体产品类
class SpringTextField : TextField
{
public override void Display()
{
Console.WriteLine("绘制一个春天风格文本框!");
}
}
//夏天文本框:具体产品类
class SummerTextField : TextField
{
public override void Display()
{
Console.WriteLine("绘制一个夏天风格文本框!");
}
}
//春天组合框:具体产品类
class SpringComboBox : ComboBox
{
public override void Display()
{
Console.WriteLine("绘制一个春天风格组合框!");
}
}
//夏天组合框:具体产品类
class SummerComboBox : ComboBox
{
public override void Display()
{
Console.WriteLine("绘制一个夏天风格组合框!");
}
}
//春天风格皮肤工厂:具体工厂类
class SpringFactory : SkinFactory
{
//创建春天风格按钮
public override Button CreateButton()
{
return new SpringButton();
}
//创建春天风格文本框
public override TextField CreateTextField()
{
return new SpringTextField();
}
//创建春天风格组合框
public override ComboBox CreateComboBox()
{
return new SpringComboBox();
}
}
//夏天风格皮肤工厂:具体工厂类
class SummerFactory : SkinFactory
{
//创建春天风格按钮
public override Button CreateButton()
{
return new SummerButton();
}
//创建春天风格文本框
public override TextField CreateTextField()
{
return new SummerTextField();
}
//创建春天风格组合框
public override ComboBox CreateComboBox()
{
return new SummerComboBox();
}
}
Button btn;
TextField txt;
ComboBox box;
SummerFactory factory = new SummerFactory();
btn = factory.CreateButton();
btn.Display();
txt = factory.CreateTextField();
txt.Display();
box = factory.CreateComboBox();
box.Display();
SpringFactory factory1 = new SpringFactory();
btn = factory1.CreateButton();
btn.Display();
txt = factory1.CreateTextField();
txt.Display();
box = factory1.CreateComboBox();
box.Display();
优缺点
优点:增加新的产品族很方便,无需修改已有系统,符合开闭原则
缺点:增加新的产品等级结构很麻烦,需要修改所有工厂角色,不符合开闭原则
体现了开闭原则的倾斜性。
应用场景
1、属于同一产品族的产品将在一起使用
2、产品等级结构稳定,在设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的等级结构
3、系统中有多于一个的产品族,但每次只使用其中某一产品族
原型模式
定义
通过复制一个已有对象来获取更多相同或者相似的对象。
原型模式可以提高相同类型对象的创建效率,简化创建过程。
原型模式的动机:通过复制一个原型对象得到多个与原型对象一模一样的新对象。
角色组成
Prototype(抽象原型类) | 声明克隆方法的接口,是所有具体原型类的公共父类 |
ConcretePrototype(具体原型类) | 实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。 |
Client(客户类) | 实例化一个原型对象,再调用该对象的克隆方法得到多个相同的对象。 |
浅克隆和深克隆
浅克隆(Shallow Clone)
当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
abstract class Prototype
{
public abstract Prototype Clone();
}
internal class PrototypeA:Prototype
{
public string name;
public int price;
public int[] array = new int[10];
public override Prototype Clone()
{
return (PrototypeA)this.MemberwiseClone();
}
}
PrototypeA protoA = new PrototypeA();
protoA.name = "alan";
protoA.price = 100;
var temp = (PrototypeA)protoA.Clone();
Console.WriteLine($"{protoA.GetHashCode()} " +
$" {temp.GetHashCode()} " +
$" {protoA == temp} " +
$" {protoA.array == temp.array} " +
$" {protoA.name}"+
$" {temp.name}"+
$" {protoA.price}" +
$" {temp.price}"
);
深克隆(Deep Clone)
将原型对象的值类型成员变量和引用类型的成员变量都复制一份给克隆对象。
直接重新创建新的引用对象实现深拷贝
internal class PrototypeA:ICloneable
{
public string name;
public int price;
public int[] array = new int[10];
public object Clone()
{
var obj = (PrototypeA)this.MemberwiseClone();
obj.array = new int[10];
return obj;
}
}
建造者模式
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
作用:将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需知道所需建造者的类型即可。
角色组成
Builder(抽象建造者) | 声明两类方法的抽象接口: 1、产品各部件的创建方法 2、GetResult,返回复杂对象的方法 |
ConcreteBuilder (具体建造者) | 实现抽象建造者接口 |
Product(产品) | 复杂对象的模板 |
Director(指挥者) | 提供Construct构建方法,安排复杂对象的建造次序,调用抽象建造者对象的部件构造与装配方法,完成对象建造 客户端只需要与指挥者进行交互 通过指挥者的构造函数或者Settter方法传入具体建造者 |
代码示例
//角色类 (产品角色)
public class Actor
{
public string typeName;//角色类型
public string weaponType;//武器类型
public string clothType;//服装类型
public void Print()
{
Console.WriteLine($"角色类型:{typeName}\n武器类型:{weaponType}\n服装类型:{clothType}\n");
}
}
//抽象建造者
public abstract class ActorBuilder
{
protected Actor actor = new Actor();
public abstract void BuildActorType();
public abstract void BuildWeaponType();
public abstract void BuildClothType();
public abstract Actor GetResult();
}
//战士类 具体建造者
public class HeroBuilder : ActorBuilder
{
public override void BuildActorType()
{
actor.typeName = "战士";
}
public override void BuildWeaponType()
{
actor.weaponType = "大剑";
}
public override void BuildClothType()
{
actor.clothType = "盔甲";
}
public override Actor GetResult()
{
return actor;
}
}
//法师类 具体建造者
public class MageBuilder : ActorBuilder
{
public override void BuildActorType()
{
actor.typeName = "法师";
}
public override void BuildWeaponType()
{
actor.weaponType = "魔杖";
}
public override void BuildClothType()
{
actor.clothType = "斗篷";
}
public override Actor GetResult()
{
return actor;
}
}
//辅助类 具体建造者
public class TankBuilder : ActorBuilder
{
public override void BuildActorType()
{
actor.typeName = "辅助";
}
public override void BuildWeaponType()
{
actor.weaponType = "盾牌";
}
public override void BuildClothType()
{
actor.clothType = "盔甲";
}
public override Actor GetResult()
{
return actor;
}
}
//指挥类
public class ActorDirector
{
public Actor Construct(ActorBuilder builder)
{
Actor actor;
builder.BuildActorType();
builder.BuildWeaponType();
builder.BuildClothType();
actor = builder.GetResult();
return actor;
}
}
ActorDirector ad =new ActorDirector();
ActorBuilder ab = new TankBuilder();
var result = ad.Construct(ab);
result.Print();
应用场景
1、要求所创建的产品一半具有较多的共同点
2、需要创建一个包含多个组成部件的复杂对象,使用相同的构建过程构建不同的产品
结构型模式
Structural Pattern
目标:将现有类或对象组织在一起形成更强大的结构
共有7种结构型设计模式
模式 | 类型 | 处理哪种问题 | 设计原则体现 | 学习难度 | 使用频率 |
外观模式 (Facade) | 对象结构型模式 | 一个客户类需要和多个业务类交互,而这些需要交互的业务类经常会作为一个整体出现 | 迪米特法则 | ⭐ | ⭐⭐⭐⭐⭐ |
适配器模式 (Adapter) | 对象对象结构型模式&& 类结构型模式型模式 | 如果系统中存在不兼容的接口,可以通过引入一个适配器来使得原本因为接口不兼容而不能在一起工作的两个类可以协同工作 | ⭐⭐ | ⭐⭐⭐⭐ | |
组合模式 (Composite) | 对象结构型模式 | 使得用户可以一致性地处理整个树形结构或者树形结构的一部分 | ⭐⭐⭐ | ⭐⭐⭐⭐ | |
代理模式 (Proxy) | 对象结构型模式 | 当用户无法直接访问某个对象或者访问某个对象存在困难时,可以通过一个代理对象来间接访问 | ⭐⭐⭐ | ⭐⭐⭐⭐ | |
桥接模式 (Bridge) | 对象结构型模式 | 处理有多个变化维度的系统 | ⭐⭐⭐ | ⭐⭐⭐ | |
装饰模式 (Decorator) | 对象结构型模式 | 用于替代继承的技术,给对象动态增加职责,使对象之间的关联关系取代类之间的继承关系 | 开闭原则 | ⭐⭐⭐ | ⭐⭐⭐ |
享元模式 (Flyweight) | 对象结构型模式 | 系统中存在大量相同或者相似的对象时,通过共享技术实现相同或相似的细粒度对象的复用,从而节约内存,提高系统性能 | ⭐⭐⭐⭐ | ⭐ |
外观模式
定义
1、为子系统中的一组接口提供提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
2、又称为门面模式,是一种对象结构型模式,通过引入一个新的外观角色来降低原有系统的复杂度,同时降低客户类与子系统的耦合度。
3、外观模式并不给系统增加任何新功能,它仅仅是简化调用接口
角色组成
Facade(外观角色) | 维持了对子系统对象的引用,客户端可以通过外观类来间接调用子系统对象的业务方法 |
SubSystem(子系统角色) | 是一个广义的概念,可以是一个类,一个功能模块、系统的一个组成部分或者一个完整的系统 |
//子系统类
class SubSystemA
{
public void MethodA()
{
Console.WriteLine("A系统操作方法!");
}
}
//子系统类
class SubSystemB
{
public void MethodB()
{
Console.WriteLine("B系统操作方法!");
}
}
//子系统类
class SubSystemC
{
public void MethodC()
{
Console.WriteLine("C系统操作方法!");
}
}
//外观类
class Facade
{
private SubSystemA systemA = new SubSystemA();
private SubSystemB systemB = new SubSystemB();
private SubSystemC systemC = new SubSystemC();
public void Method()
{
systemA.MethodA();
systemB.MethodB();
systemC.MethodC();
}
}
应用实例
//文件读取类 (子系统类)
class FileReader
{
public string Read(string fileNameSrc)
{
string str = "锄禾日当午,汗滴禾下土。谁知盘中餐,粒粒皆辛苦。";
Console.WriteLine("读取文件操作:\n"+str);
return str;
}
}
//文件加密类 (子系统类)
class CipherMachine
{
public string Encrypt(string plainText)
{
Console.WriteLine("文件加密操作:\n");
string result = "***" + plainText + "***";
return result;
}
}
//文件保存类 (子系统类)
class FileWriter
{
public void Write(string encryptText,string fileNameDes)
{
Console.WriteLine("文件保存操作:\n");
Console.WriteLine($"将文件:{encryptText}保存到路径:{fileNameDes}下了!");
}
}
//加密外观类
class EncryptFacade
{
private FileReader reader;
private CipherMachine cipher;
private FileWriter writer;
public EncryptFacade()
{
reader = new FileReader();
cipher = new CipherMachine();
writer = new FileWriter();
}
public void FileEncrypt(string fileNameSrc,string fileNameDes)
{
string plainStr = reader.Read(fileNameSrc);
string encryptStr = cipher.Encrypt(plainStr);
writer.Write(encryptStr, fileNameDes);
}
}
EncryptFacade encryptFacade = new EncryptFacade();
encryptFacade.FileEncrypt("策划方案.doc", "C:/Windows/我的文件夹");
抽象外观类
//文件读取类 (子系统类)
class FileReader
{
public string Read(string fileNameSrc)
{
string str = "锄禾日当午,汗滴禾下土。谁知盘中餐,粒粒皆辛苦。";
Console.WriteLine("读取文件操作:\n"+str);
return str;
}
}
//文件加密类 (子系统类)
class CipherMachine
{
public string Encrypt(string plainText)
{
Console.WriteLine("文件加密操作:\n");
string result = "***" + plainText + "***";
return result;
}
}
//新增高级文件加密类 (子系统类)
class AdvancedCipherMachine
{
public string Encrypt(string plainText)
{
Console.WriteLine("高级文件加密操作:\n");
string result = ">>>" + plainText + "<<<";
return result;
}
}
//文件保存类 (子系统类)
class FileWriter
{
public void Write(string encryptText,string fileNameDes)
{
Console.WriteLine("文件保存操作:\n");
Console.WriteLine($"将文件:{encryptText}保存到路径:{fileNameDes}下了!");
}
}
//抽象外观类
abstract class AbstractFacade
{
public abstract void FileEncrypt(string fileNameSrc, string fileNameDes);
}
//加密外观类
class EncryptFacade: AbstractFacade
{
private FileReader reader;
private CipherMachine cipher;
private FileWriter writer;
public EncryptFacade()
{
reader = new FileReader();
cipher = new CipherMachine();
writer = new FileWriter();
}
public override void FileEncrypt(string fileNameSrc,string fileNameDes)
{
string plainStr = reader.Read(fileNameSrc);
string encryptStr = cipher.Encrypt(plainStr);
writer.Write(encryptStr, fileNameDes);
}
}
//高级加密外观类
class AdvancedEncryptFacade : AbstractFacade
{
private FileReader reader;
private AdvancedCipherMachine cipher;
private FileWriter writer;
public AdvancedEncryptFacade()
{
reader = new FileReader();
cipher = new AdvancedCipherMachine();
writer = new FileWriter();
}
public override void FileEncrypt(string fileNameSrc, string fileNameDes)
{
string plainStr = reader.Read(fileNameSrc);
string encryptStr = cipher.Encrypt(plainStr);
writer.Write(encryptStr, fileNameDes);
}
}
AbstractFacade facade = new AdvancedEncryptFacade();
facade.FileEncrypt("策划方案.doc", "C:/Windows/我的文件夹");
优缺点
优点:通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,使得子系统与客户端的耦合度降低,且客户端调用非常方便
缺点:在增加或者溢出子系统时,需要对外观类进行修改,也可能需要对客户类进行修改,在一定程度上不符合开闭原则(通过引入抽象外观类进行解决)
使用场景
一个客户类需要和多个业务类交互,而这些需要交互的业务类经常会作为一个整体出现
适配器模式
定义
1、将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
2、别名:包装器模式(Wrapper)模式,定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。
3、作用:如果系统中存在不兼容的接口,可以通过引入一个适配器来使得原本因为接口不兼容而不能在一起工作的两个类可以协同工作。
角色组成
Target(目标抽象类) | 定义客户所需接口 在类适配器中,为支持多继承必须为接口 |
Adapter(适配器类) | 作为一个转换器,对Adaptee和Target进行适配 适配器时适配器模式的核心 在类适配器中,它通过实现Target接口并继承Adaptee类来使得二者产生联系。 在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。 |
Adaptee(适配者类) | 被适配的角色,一般是一个具体类,包含了客户希望使用的业务方法。 |
适配器模式分为类适配器模式和对象适配器模式
代码实现
/// <summary>
/// 目标抽象接口
/// </summary>
interface ScoreOperation
{
void Sort(int[] arr);
int Search(int[] arr, int key);
}
/// <summary>
/// 快排算法 适配者角色
/// </summary>
class QuickSortClass
{
public void QuickSort(int[] arr)
{
QSort(arr, 0, arr.Length - 1);
}
private void QSort(int[] arr, int low, int high)
{
if (low < high)
{
int pivotIndex = GetPivotIndex(arr, low, high);
QSort(arr, low, pivotIndex - 1);
QSort(arr, pivotIndex + 1, high);
}
}
private int GetPivotIndex(int[] arr,int low,int high)
{
var pivotKey = arr[low];
while(low < high)
{
while(low < high && arr[high] >= pivotKey)
{
high--;
}
(arr[low], arr[high]) = (arr[high], arr[low]);
while(low < high && arr[low] <= pivotKey)
{
low++;
}
(arr[low], arr[high]) = (arr[high], arr[low]);
}
return low;
}
}
/// <summary>
/// 二分查找 适配者角色
/// </summary>
class BinarySearchClass
{
public int BinarySearch(int[] arr,int value)
{
int low = 0;
int high = arr.Length - 1;
while(low <= high)
{
int mid = (high - low) / 2 + low;
if (value == arr[mid])
{
return mid;
}
else if (value < arr[mid])
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
return -1;
}
}
/// <summary>
/// 适配器类
/// </summary>
class OperationAdapter : ScoreOperation
{
private QuickSortClass quickSortClass;
private BinarySearchClass binarySearchClass;
public OperationAdapter()
{
quickSortClass = new QuickSortClass();
binarySearchClass = new BinarySearchClass();
}
public void Sort(int[] arr)
{
quickSortClass.QuickSort(arr);
}
public int Search(int[] arr,int value)
{
return binarySearchClass.BinarySearch(arr, value);
}
}
ScoreOperation scoreOperation;
scoreOperation = new OperationAdapter();
int[] arr = { 77, 65, 79, 83, 92, 80, 71, 88, 87, 94, 55, 89, 92 };
HelloWorld.PrintArray(arr);
scoreOperation.Sort(arr);
HelloWorld.PrintArray(arr);
var index = scoreOperation.Search(arr, 55);
Console.WriteLine(index);
优缺点
1、提高了适配者的复用性
2、可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合开闭原则
组合模式
定义
1、组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。又称为 部分-整体模式,属于对象结构型模式。
2、动机:使得用户可以一致性地处理整个树形结构或者树形结构的一部分,描述如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象。
3、主要特点:递归组合、树状结构、统一处理所有对象
角色组成
Component(抽象构件) | 为叶子构件和容器构件对象声明接口,在该角色中包含所有子类共有行为地声明和实现。 |
Leaf(叶子构件) | 叶子节点没有子节点,实现抽象构建中定义的行为 |
Composite(容器构建) | 容器节点包含子节点(可以是叶子节点也可以是容器节点)。提供一个集合用于存储子节点,实现抽象构件中定义的行为。在其业务方法中可以递归调用其子节点的业务方法。 |
//抽象构件
abstract class Component
{
public abstract void Operation();
}
//叶子构件
class Leaf : Component
{
public override void Operation()
{
Console.WriteLine("叶子节点的操作方法!");
}
}
//容器构件
class Composite : Component
{
List<Component> components = new List<Component>();
public void AddChild(Component child)
{
components.Add(child);
}
public void RemoveChild(Component child)
{
components.Remove(child);
}
public override void Operation()
{
foreach (Component child in components)
{
child.Operation();
}
}
}
//客户端代码
Composite composite = new Composite();
Leaf leaf1 = new Leaf();
composite.AddChild(leaf1);
leaf1.Operation();
应用实例
//抽象文件类 (抽象构件)
abstract class AbstractFile
{
public abstract void KillVirus();
}
//图像文件类(叶子构件)
class ImageFile:AbstractFile
{
public string name;
public ImageFile(string _name)
{
name = _name;
}
public override void KillVirus()
{
Console.WriteLine($"对图像文件:{name},进行杀毒操作!");
}
}
//文本文件类(叶子构件)
class TextFile : AbstractFile
{
public string name;
public TextFile(string _name)
{
name = _name;
}
public override void KillVirus()
{
Console.WriteLine($"对文本文件:{name},进行杀毒操作!");
}
}
//视频文件类(叶子构件)
class VideoFile : AbstractFile
{
public string name;
public VideoFile(string _name)
{
name = _name;
}
public override void KillVirus()
{
Console.WriteLine($"对视频文件:{name},进行杀毒操作!");
}
}
//文件夹类 (容器构件)
class Folder : AbstractFile
{
public string name;
public Folder(string _name)
{
name = _name;
}
public List<AbstractFile> fileList = new List<AbstractFile>();
public void Add(AbstractFile file)
{
fileList.Add(file);
}
public void Remove(AbstractFile file)
{
fileList.Remove(file);
}
public override void KillVirus()
{
Console.WriteLine($"************对文件夹:{name},进行杀毒操作!************");
foreach ( AbstractFile file in fileList )
{
file.KillVirus();
}
}
}
Folder folder1 = new Folder("旅游文件夹");
folder1.Add(new ImageFile("风景图片.jpg"));
folder1.Add(new ImageFile("自拍照片.jpg"));
folder1.Add(new TextFile("旅行日记.txt"));
folder1.Add(new VideoFile("旅行视频.mov"));
Folder folder2 = new Folder("学习文件夹");
Folder folder3 = new Folder("学习视频文件夹");
folder3.Add(new VideoFile("C#学习视频.mov"));
folder3.Add(new VideoFile("Unity教程.mov"));
folder3.Add(new VideoFile("Lua教程.mp4"));
folder2.Add(folder3);
folder2.Add(new TextFile("数据结构与算法学习笔记.txt"));
folder2.Add(new ImageFile("设计模式思维导图.png"));
Folder mainFolder = new Folder("main");
mainFolder.Add(folder1);
mainFolder.Add(folder2);
mainFolder.KillVirus();
分类
分为透明组合模式和安全组合模式
透明组合模式 | 在抽象构件中声明了用于管理成员对象的方法 |
安全组合模式 | 在抽象构件中没有声明用于管理成员对象的方法,而是在容器构件中声明并实现这些方法。 |
优点
简化了客户端代码,客户端一致地处理一个组合结构或者单个对象
增加新的容器构件和叶子构件很方便,无须修改原有代码,符合开闭原则
适用环境
1、需要处理一个树形结构,例如:操作系统中的目录结构、软件中的菜单结构、公司组织架构
2、希望客户端一致地处理整体和部分(叶子对象和容器对象)
3、系统能够分离出叶子对象和容器对象
代理模式
定义
1、给某一对象提供要给代理或者占位符,并由代理对象来控制对原对象的访问
2、是一种对象结构型模式。在代理模式中引入了一个新的代理对象,代理对象在客户端对象和目标对象之间起到中介作用,它去掉客户不能看到的内容和服务或者增添客户需要的额外的新服务。
角色组成
Subject(抽象主题角色) | 声明了代理主题类和真实主题类的公共方法 |
Proxy(代理主题角色) | 包含真实主题的引用 可以调用真实主题角色对象中的操作,或者在之前或之后增加其他操作逻辑,对功能进行扩展或者约束 |
RealSubject(真实主题角色) | 包含具体的业务操作 |
//抽象主题类
abstract class Subject
{
public abstract void Request();
}
//真实主题类
class RealSubject:Subject
{
public override void Request()
{
//业务方法具体实现代码
Console.WriteLine("真实主题类的业务方法");
}
}
class Proxy : Subject
{
//维持一个对真实主题对象的引用
private RealSubject obj = new RealSubject();
public void PreRequest()
{
Console.WriteLine("在代理逻辑前的操作!");
}
public override void Request()
{
PreRequest();
obj.Request();//调用真实主题对象的方法
PostRequest();
}
public void PostRequest()
{
Console.WriteLine("在代理逻辑后的操作!");
}
}
Proxy proxy = new Proxy();
proxy.Request();
应用实例
//抽象查询类 抽象主题角色
abstract class Searcher
{
public abstract string DoSearch(string userId,string keyword);
}
//具体查询类 (真实主题角色)
class RealSearcher: Searcher
{
//模拟查询商务信息
public override string DoSearch(string userId, string keyword)
{
//业务方法具体实现代码
Console.WriteLine($"用户{userId}使用关键词{keyword}查询商务信息!");
return "返回具体内容";
}
}
class ProxySearcher : Searcher
{
//维持一个对真实主题对象的引用
private RealSearcher obj = new RealSearcher();
//扩展业务类的引用
private AccessValidator validator;
private Logger logger;
public override string DoSearch(string userId, string keyword)
{
if (Validate(userId))
{
var result = obj.DoSearch(userId, keyword);//调用真实主题对象的方法
Log(userId);
return result;
}
else
{
return null;
}
}
//创建访问验证对象并调用Validate方法实现身份验证
public bool Validate(string userId)
{
if(validator == null)
{
validator = new AccessValidator();
}
return validator.Validate(userId);
}
//创建日志记录对象并调用Log方法实现日志记录
public void Log(string userId)
{
if(logger == null)
{
logger = new Logger();
}
logger.Log(userId);
}
}
//身份验证类 (业务类)
class AccessValidator
{
//模拟登录验证
public bool Validate(string userId)
{
Console.WriteLine($"在数据库中验证用户{userId}是否合法用户!");
if(userId == "小明")
{
Console.WriteLine("验证通过,登录成功!");
return true;
}
else
{
Console.WriteLine("验证未通过,登录失败!");
return false;
}
}
}
//日志记录类 (业务类)
class Logger
{
//模拟实现日志记录
public void Log(string userId)
{
Console.WriteLine($"更新数据库,用户{userId}查询次数加1!");
}
}
ProxySearcher searcher = new ProxySearcher();
searcher.DoSearch("小明", "设计模式");
优缺点
优点
1、可以方便地增加和更改代理类无须修改源代码,符合开闭原则
2、降低系统耦合度,协调调用者和被调用者
桥接模式
定义
1、将抽象部分与它的实现部分解耦,使得两者都能够独立变化
2、一种对象结构型模式,又称为柄体模式或接口模式
3、用于处理多层继承的问题,用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效控制了系统中类的个数
角色组成
Abstraction(抽象类) | 通常是抽象类而不是接口,与之关系最密切的维度设计为抽象类角色 维持一个实现类接口对象引用 再通过构造方法或者Setter方法注入实体实现类对象 |
RefinedAbstraction(扩充抽象类) | |
Implementor(实现类接口) | 适用接口实现 |
ConcreteImplementor(具体实现类) |
应用实例
//支付类型
enum PayType
{
WeChatPay,//微信支付
AliPay,//支付宝支付
UnionPay,//银联支付
}
//商品类型
enum ProductType
{
Book,//书籍
Toy,//玩具
Food,//食品
Clothes,//服装
}
//支付方式接口:实现类接口
interface IPayment
{
public void Pay();
}
//商品抽象类:抽象类角色
abstract class Product
{
protected IPayment payment;
public abstract void Buy();
//设置支付方式 注入实现类接口对象
public void SetPayment(IPayment payment)
{
this.payment = payment;
}
}
//书籍商品类:扩充抽象类
class Book : Product
{
public override void Buy()
{
Console.WriteLine("选中商品--书籍");
payment.Pay();
}
}
//玩具商品类:扩充抽象类
class Toy : Product
{
public override void Buy()
{
Console.WriteLine("选中商品--玩具");
payment.Pay();
}
}
//食品商品类:扩充抽象类
class Food : Product
{
public override void Buy()
{
Console.WriteLine("选中商品--食品");
payment.Pay();
}
}
//服装商品类:扩充抽象类
class Clothes : Product
{
public override void Buy()
{
Console.WriteLine("选中商品--服装");
payment.Pay();
}
}
//微信支付类:具体实现类
class WeChatPay : IPayment
{
public void Pay()
{
Console.WriteLine("使用微信支付,成功购买^-^");
}
}
//支付宝支付类:具体实现类
class AliPay : IPayment
{
public void Pay()
{
Console.WriteLine("使用支付宝支付,成功购买^-^");
}
}
//银联支付类:具体实现类
class UnionPay : IPayment
{
public void Pay()
{
Console.WriteLine("使用银联支付,成功购买^-^");
}
}
public static void BuyProduct(ProductType productType,PayType payType)
{
IPayment payment=null;
Product product=null;
switch (productType)
{
case ProductType.Book:
product = new Book();
break;
case ProductType.Toy:
product = new Toy();
break;
case ProductType.Food:
product = new Food();
break;
case ProductType.Clothes:
product = new Clothes();
break;
}
switch (payType)
{
case PayType.WeChatPay:
payment = new WeChatPay();
break;
case PayType.AliPay:
payment = new AliPay();
break;
case PayType.UnionPay:
payment = new UnionPay();
break;
}
product.SetPayment(payment);
product.Buy();
}
优缺点
优点:用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效控制了系统中类的个数
适用环境
处理有多个变化维度的系统
装饰模式
定义
1、动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。
2、是一种用于替代继承的技术。通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系.
3、在不改变一个对象本身功能的基础上给对象增加额外的新行为。
角色组成
Component(抽象构件) | 是具体构件和抽象装饰类的共同父类 |
ConcreteComponent(具体构件) | 抽象构件类的子类,实现抽象构件中声明的方法,装饰类可以给它增加额外的职责 |
Decorator(抽象装饰类) | 抽象构件类的子类,用于给具体构件增加职责。 维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法。 |
ConcreteDecorator(具体装饰类) | 抽象装饰类的子类,负责向构件添加新的职责 |
//抽象构件
abstract class Component
{
public abstract void Operation();
}
//具体构件
class ConcreteComponent : Component
{
public override void Operation()
{
Console.WriteLine("原有功能实现!");
}
}
//抽象装饰类
abstract class Decorator : Component
{
//维持一个对抽象构件对象的引用
private Component component;
//注入一个抽象构件类型的对象
public Decorator(Component component)
{
this.component = component;
}
public override void Operation()
{
//调用原有业务的方法
component.Operation();
}
}
//具体装饰类
class ConcreteDecorator : Decorator
{
public ConcreteDecorator(Component component):base(component)
{
}
public override void Operation()
{
base.Operation();
AddExtendLogic();
}
//扩展新增职责
private void AddExtendLogic()
{
Console.WriteLine("扩展新增职责");
}
}
//测试代码
Component component = new ConcreteComponent();
component.Operation();
Component decorator = new ConcreteDecorator(component);
decorator.Operation();
应用实例
//抽象构件类
abstract class VisualComponent
{
public abstract void Display();
}
//窗体界面(具体构件类)
class Window:VisualComponent
{
public override void Display()
{
Console.WriteLine("绘制一个窗体界面");
}
}
//文本框界面(具体构件类)
class TextBox : VisualComponent
{
public override void Display()
{
Console.WriteLine("绘制一个文本框");
}
}
//列表框界面(具体构件类)
class ListBox : VisualComponent
{
public override void Display()
{
Console.WriteLine("绘制一个列表框");
}
}
//抽象装饰类
abstract class Decorator:VisualComponent
{
private VisualComponent visualCom;
public Decorator(VisualComponent component)
{
visualCom = component;
}
public override void Display()
{
this.visualCom.Display();
}
}
// 滚动条装饰类 (具体装饰类)
class ScrollBarDecorator:Decorator
{
public ScrollBarDecorator(VisualComponent component) : base(component)
{
}
public override void Display()
{
base.Display();
SetScrollBar();
}
private void SetScrollBar()
{
Console.WriteLine("添加滚动条!");
}
}
//黑色边框装饰类 具体装饰类
class BlackBorderDecorator : Decorator
{
public BlackBorderDecorator(VisualComponent component) : base(component)
{
}
public override void Display()
{
base.Display();
SetBlackBorder();
}
private void SetBlackBorder()
{
Console.WriteLine("添加黑色边框!");
}
}
//给窗体添加滚动条和黑色边框
VisualComponent visualComponent = new Window();
VisualComponent newWindow = new ScrollBarDecorator(visualComponent);
newWindow = new BlackBorderDecorator(newWindow);
newWindow.Display();
//给文本框添加黑色边边框
VisualComponent visualComponent1 = new TextBox();
VisualComponent newText = new BlackBorderDecorator(visualComponent);
newText.Display();
//给列表框添加滚动条和黑色边框
VisualComponent visualComponent2 = new ListBox();
VisualComponent newListBox = new ScrollBarDecorator(visualComponent2);
newListBox.Display();
适用场景
1、在不影响其他对象的情况下,动态地给单个对象添加职责。
2、当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以适用装饰模式。
不能采用继承的情况主要有两种:
1、系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈现爆炸性增长。
2、类已定义为不能被集成。(例如 密封类)
享元模式
定义
1、运用共享技术有效地支持大量细粒度对象的复用。可以节约内存,提高性能。
2、享元模式以共享的方式高效地支持大量细粒度对象地重用,享元对象能做到共享的关键是区分了内部状态和外部状态:
内部状态(Intrinsic State):不会随着环境改变而改变的状态,可以共享
外部状态(Extrinsic State):随着环境改变而改变、不可共享的状态。通常由客户端保存外部状态,在需要使用的时候再传入享元对象的内部。
例如:一个字符对象表示"a","a"即为内部状态,字符的大小、颜色即为外部状态。
角色组成
Flyweight(抽象享元类) | 声明具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法设置外部数据(外部状态) |
ConcreteFlyweight(具体享元类) | 为内部状态提供存储空间。通常可以结合单例模式来设计,为每一个具体享元类提供唯一的享元对象 |
UnsharedConcreteFlyweight(非共享具体享元类) | |
FlyweightFactory(享元工厂类) | 用于创建并管理享元对象,针对抽象享元类编程。将具体享元对象存储在一个享元对象(键值对)。 |
//抽象享元类
abstract class Flyweight
{
public abstract void Operation(string extrinsicState);
}
//具体享元类
class ConcreteFlyweight : Flyweight
{
//内部状态
private string intrinsicState;
public ConcreteFlyweight(string intrinsicState)
{
this.intrinsicState = intrinsicState;
}
//用于外部状态设置
public override void Operation(string extrinsicState)
{
//实现业务方法
Console.WriteLine($"内部状态是:{intrinsicState} 外部状态是:{extrinsicState}");
}
}
//非共享具体享元类
class UnsharedConcreteFlyweight : Flyweight
{
public override void Operation(string extrinsicState)
{
//实现业务方法
}
}
//享元工厂类
class FlyweightFactory
{
//定义一个hashtable存储享元对象,实现享元池子
private Hashtable flyweightPool;
public FlyweightFactory()
{
flyweightPool = new Hashtable();
}
//获取享元对象
public Flyweight GetFlyweightObj(string key)
{
if (flyweightPool.ContainsKey(key))
{
Console.WriteLine("存在过了 " + key);
return (Flyweight)flyweightPool[key];
}
else
{
Console.WriteLine("新创建 " + key);
Flyweight obj = new ConcreteFlyweight(key);
flyweightPool.Add(key, obj);
return obj;
}
}
}
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight;
flyweight = factory.GetFlyweightObj("星期一");
flyweight.Operation("草莓");
flyweight = factory.GetFlyweightObj("星期二");
flyweight.Operation("西瓜");
flyweight = factory.GetFlyweightObj("星期一");
flyweight.Operation("香蕉");
应用实例
struct Position
{
public int x;
public int y;
public Position(int x, int y)
{
this.x = x;
this.y = y;
}
}
//抽象享元类
abstract class IgoChessman
{
public abstract string GetColor();
public void Display(Position pos)
{
Console.WriteLine($"棋子颜色: {this.GetColor()} 坐标:[{pos.x},{pos.y}]");
}
}
//黑棋子类 (具体享元类)
class BlackIgoChessman : IgoChessman
{
//内部状态
private string chessColor;
public BlackIgoChessman(string chessColor)
{
this.chessColor = chessColor;
}
//用于外部状态设置
public override string GetColor()
{
//实现业务方法
Console.WriteLine($"内部状态是:{chessColor} 外部状态是:{chessColor}");
return chessColor;
}
}
//白棋子 (具体享元类)
class WhiteIgoChessman : IgoChessman
{
//内部状态
private string chessColor;
public WhiteIgoChessman(string chessColor)
{
this.chessColor = chessColor;
}
//用于外部状态设置
public override string GetColor()
{
//实现业务方法
Console.WriteLine($"内部状态是:{chessColor} 外部状态是:{chessColor}");
return chessColor;
}
}
//享元工厂类
class IgoChessmanFactory
{
private static IgoChessmanFactory instance = new IgoChessmanFactory();
public static IgoChessmanFactory GetInstance()
{
return instance;
}
//定义一个hashtable存储享元对象,实现享元池子
private Hashtable chessmanPool;
private IgoChessmanFactory()
{
chessmanPool = new Hashtable();
}
//获取享元对象
public IgoChessman GetFlyweightObj(string key)
{
if (chessmanPool.ContainsKey(key))
{
Console.WriteLine("存在过了 " + key);
return (IgoChessman)chessmanPool[key];
}
else
{
IgoChessman obj;
if (key == "白")
{
obj = new WhiteIgoChessman(key);
}
else
{
obj = new BlackIgoChessman(key);
}
Console.WriteLine("新创建 " + key);
chessmanPool.Add(key, obj);
return obj;
}
}
}
var instance = IgoChessmanFactory.GetInstance();
IgoChessman igo1 = instance.GetFlyweightObj("白");
igo1.Display(new Position(1,2));
IgoChessman igo2 = instance.GetFlyweightObj("黑");
igo2.Display(new Position(4, 3));
IgoChessman igo3 = instance.GetFlyweightObj("白");
igo3.Display(new Position(5, 5));
IgoChessman igo4 = instance.GetFlyweightObj("白");
igo4.Display(new Position(6, 1));
IgoChessman igo5 = instance.GetFlyweightObj("黑");
igo5.Display(new Position(4, 2));
适用环境
一个系统有大量相同或者相似的对象,造成了内存的大量耗费。
行为型模式
Behavioral Pattern
目标:关注系统中对象之间的交互
共有11种行为型模式:
模式 | 类型 | 处理哪种问题 | 设计原则体现 | 学习难度 | 使用频率 |
观察者模式 (Observer) | 对象行为型模式 | 在一对一或者一对多的对象交互场景中,一个对象状态或行为的变化将导致其他对象的状态或行为也发生变化 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | |
策略模式 (Strategy) | 对象行为型模式 | 处理算法的封装、复用和切换 | 开闭原则 | ⭐ | ⭐⭐⭐⭐ |
命令模式 (Command) | 对象行为型模式 | 将请求发送者与请求接收者解耦,请求发送者通过命令对象来间接引用接收者 | ⭐⭐⭐ | ⭐⭐⭐⭐ | |
模板方法模式 (Template Method) | 类行为型模式 | 提供一个模板方法来定义算法框架,具体步骤的实现可以在子类中完成 | ⭐⭐ | ⭐⭐⭐ | |
状态模式 (State) | 对象行为型模式 | 系统中某个对象存在多个状态,状态之间可以切换,对象在不同状态下行为也不相同 | ⭐⭐⭐ | ⭐⭐⭐ | |
中介者模式 (Mediator) | 对象行为型模式 | 将对象之间多对多的关系转换为一对多的关系 | 迪米特法则 | ⭐⭐⭐ | ⭐⭐ |
职责链模式 (Chain of Responsibility) | 对象行为型模式 | 有多个对象可以处理同一个请求 | ⭐⭐⭐ | ⭐⭐ | |
访问者模式 (Visitor) | 对象行为型模式 | 系统的对象结构包含多个类型的对象,并且不同访问者对其所采取的操作也不相同 | ⭐⭐⭐⭐ | ⭐ | |
迭代器模式 (Iterator) | 对象行为型模式 | 用于遍历一个集合中所有的元素 | 🍏🍏🍏 | 🍏🍏🍏🍏🍏 | |
备忘录模式 (Memento) | 对象行为型模式 | 提供一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。实现撤销操作 | 🍏🍏 | 🍏🍏 | |
解释器模式 (Interpreter) | 类行为型模式 | 用于解释语言和表达式 | 🍏🍏🍏🍏🍏 | 🍏 |
观察者模式
定义
1、定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。
2、用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。
角色组成
Subject(目标) | 被观察的对象 定义一个集合,存储所有与之相依赖的观察者 提供增加和删除观察者对象的抽象方法 定义通知观察者方法 |
ConcreteSubject(具体目标) | |
Observer(观察者) | 观察者将对观察目标的改变做出反应 一般定义为接口 |
ConcreteObserver(具体观察者) | 如果在复杂情况下,具体观察者类需要用到具体目标类中的状态或属性,则需要在具体观察者类中,维持一个对具体目标类的引用 |
//抽象观察者
interface Observer
{
//只声明一个更新响应接口
void Update();
}
class ConcreteObserver:Observer
{
//实现响应方法
public void Update()
{
Console.WriteLine("观察者更新了!");
}
}
//目标类
abstract class Subject
{
//定义一个观察者集合用于存储与之相依赖的观察者对象
protected ArrayList obserers = new ArrayList();
//声明抽象注册方法,用于向观察者集合中增加一个观察者
public abstract void Attach(Observer observer);
//声明抽象注销方法,用于向观察者集合中删除一个观察者
public abstract void Detach(Observer observer);
//声明抽象通知方法
public abstract void Notify();
}
class ConcreteSubject : Subject
{
public override void Attach(Observer observer)
{
obserers.Add(observer);
}
public override void Detach(Observer observer)
{
obserers.Remove(observer);
}
//实现通知方法,让依赖的观察者进行更新
public override void Notify()
{
foreach (Observer ob in obserers)
{
ob.Update();
}
}
}
应用实例
.Net中的委托事件模型
MVC架构
适用环境
一个对象状态或行为的变化将导致其他对象的状态或行为也发生变化
涉及一对一或者一对多的对象交互场景都可以使用观察者模式
.Net中的委托事件模型是观察者模式在.Net中的经典应用
MVC架构中应用了观察者模式
策略模式
定义
定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。又称为政策模式,是一种对象行为型模式,用于算法的自由切换与扩展。
补充:
硬编码:
1、将所有算法集中在一个类中,在该类中提供多个方法,每个方法对应一个具体的算法
2、将这些算法封装在一个统一的方法中,通过if...else...等条件判断语句来进行选择
缺点:增加新算法或者更换算法都需要修改源代码;在一个类中如果封装大量算法,代码非常复杂,维护也很困难
角色组成
Context(环境类) | 是使用算法的角色 维持一个抽象策略类的引用实例 |
Strategy(抽象策略类) | |
ConcreteStrategy(具体策略类) |
应用实例
//环境类
public class Programmer
{
private SortLogic sortLogic;
public void SetSortLogic(SortLogic logic)
{
sortLogic = logic;
}
public void Sort(int[] arr)
{
sortLogic.Sort(arr);
}
}
//排序算法类:抽象策略类
public abstract class SortLogic
{
public abstract void Sort(int[] arr);
}
//冒泡排序算法:具体策略类
class BubbleSort : SortLogic
{
public override void Sort(int[] arr)
{
Console.WriteLine("使用冒泡排序:");
int i, j;
bool isSwap;
for(i = 1; i < arr.Length; i++)
{
isSwap = false;
for(j = 0; j < arr.Length - i; j++)
{
if (arr[j] > arr[j + 1])
{
(arr[j], arr[j + 1]) = (arr[j + 1], arr[j]);
isSwap = true;
}
}
if (!isSwap)
{
break;
}
}
}
}
//简单选择排序算法:具体策略类
class SimpleSelectSort : SortLogic
{
public override void Sort(int[] arr)
{
Console.WriteLine("使用简单选择排序:");
int i, j, minIndex;
for(i = 0; i < arr.Length-1; i++)
{
minIndex = i;
for (j = i + 1; j < arr.Length; j++)
{
if (arr[j] < arr[minIndex])
{
minIndex = j;
}
}
if(minIndex != i)
{
(arr[minIndex], arr[i]) = (arr[i], arr[minIndex]);
}
}
}
}
int[] arr = { 2, 7, 3, 5, 12, -11, 20 };
Programmer programmer = new Programmer();
SortLogic sortLogic;
sortLogic = new SimpleSelectSort();
PrintArray(arr);
programmer.SetSortLogic(sortLogic);
programmer.Sort(arr);
PrintArray(arr);
优缺点
优点
在不修改原有代码的基础上进行算法的选择或新增,符合开闭原则
可以避免多重条件选择语句
适用环境
涉及算法的封装、复用和切换都可以考虑使用策略模式
命令模式
定义
将一个请求封装为一个对象,从而让你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。又称为动作模式或者事务模式。
角色组成
抽象命名类(Command) | 声明了用于执行请求的Excute等方法,子类通过该方法可以调用请求接受者的相关操作。 |
具体命令类(ConcreteCommand) | 每一具体命令类对应一个接收者,创建接收者并保存 |
调用者(Invoker) | 请求的发送者,将针对抽象命令,保存一个抽象命令类的引用,通过构造函数或者Set函数对抽象命令对象进行赋值 |
接收者(Receiver) | 请求的处理者 |
//抽象命令类
abstract class Command
{
//声明执行请求的方法
public abstract void Execute();
}
//调用者:请求发送者
class Invoker
{
private Command command;
public Invoker(Command command)
{
//通过构造函数注入命令类对象
this.command = command;
}
public Command Command { get { return command; } }
//业务方法用于调用命令类的方法
public void Call()
{
command.Execute();
}
}
class ConcreteCommand : Command
{
//维持一个接收者对象
private Receiver receiver;
public ConcreteCommand()
{
this.receiver = new Receiver();
}
//调用接受者的业务处理方法
public override void Execute()
{
receiver.Action();
}
}
//接收者:请求的处理者
class Receiver
{
public void Action()
{
Console.WriteLine("对命令进行处理!");
}
}
应用实例
//系统按钮类:调用者
class FunctionBtn
{
private Command command;
public FunctionBtn(Command command)
{
this.command = command;
}
public void Click()
{
command.Execute();
}
}
//退出系统类:接收者
class SystemExitClass
{
public void Exit()
{
Console.WriteLine("退出系统!");
}
}
//调整音量系统类:接收者
class SystemVolumeClass
{
public void ControlVolume()
{
Console.WriteLine("调整系统音量!");
}
}
//帮助文档类:接收者
class DisplayHelpClass
{
public void Display()
{
Console.WriteLine("显示帮助文档!");
}
}
//抽象命令类
abstract class Command
{
public abstract void Execute();
}
//具体命令类
class ExitCommand:Command
{
private SystemExitClass ctrl;
public ExitCommand()
{
ctrl = new SystemExitClass();
}
public override void Execute()
{
ctrl.Exit();
}
}
//帮助文档命令类
class HelpCommand : Command
{
private DisplayHelpClass ctrl;
public HelpCommand()
{
ctrl = new DisplayHelpClass();
}
public override void Execute()
{
ctrl.Display();
}
}
//调节音量命令类
class VolumeCommand : Command
{
private SystemVolumeClass ctrl;
public VolumeCommand()
{
ctrl = new SystemVolumeClass();
}
public override void Execute()
{
ctrl.ControlVolume();
}
}
Command command = new VolumeCommand();
FunctionBtn function = new FunctionBtn(command);
function.Click();
优缺点
优点
请求者和接收者之间实现了完全解耦,降低了系统的耦合度。
比较方便地增加新的命令处理,无须修改原有代码,满足开闭原则的要求。
缺点
导致系统会有过多的类,针对每一个请求接收者的调用操作都需要设计一个具体命令类。
模板方法模式
定义
1、定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些步骤。
2、是一种基于继承的代码复用技术,是一种类行为型模式
3、结构最简单的行为型设计模式
角色组成
AbstractClass(抽象类) | 定义一系列具体操作,可具体可抽象 实现一个模板方法来定义一个算法的框架(基本方法的组合执行),为具体方法,所以模板方法模式的抽象层只能是抽象类。 |
ConcreteClass(具体子类) |
模板方法:定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或者一个总行为的方法,是具体方法。
基本方法:实现算法各个步骤的方法。分为3种:抽象方法、具体方法、钩子方法。
抽象方法:父类声明,子类继承实现
具体方法:父类实现,子类覆盖或继承
钩子方法:分为两类:1、返回Bool类型对某个条件进行判断控制逻辑执行(一般命名为IsXXX()) 2、实现体为空的具体方法,子类可以根据需要进行覆盖或继承。
应用实例
//抽象类
abstract class Account
{
//验证用户信息:基本方法
public bool Validate(string account, string password)
{
if(account == "小明" && password == "123456")
{
return true;
}
else
{
return false;
}
}
//计算利息:抽象方法
public abstract void CalculateInterest();
//系统显示利息:具体方法
public void DisplayInfo()
{
Console.WriteLine("显示利息!");
}
public virtual bool IsSavingCount()
{
return false;
}
//利息计算模块框架逻辑:模板方法
public void Handle(string account,string password)
{
if(!Validate(account, password))
{
Console.WriteLine("用户验证未通过!");
return;
}
if (IsSavingCount())
{
Console.WriteLine("感谢您存定期!");
}
CalculateInterest();
DisplayInfo();
}
}
//活期账户类;具体子类
class CurrentAccount : Account
{
public override void CalculateInterest()
{
Console.WriteLine("按活期利率计算利息!");
}
}
//定期账户类;具体子类
class SavingAccount : Account
{
public override void CalculateInterest()
{
Console.WriteLine("按定期利率计算利息!");
}
public override bool IsSavingCount()
{
return true;
}
}
Account account = new CurrentAccount();
account.Handle("小明", "123456");
状态模式
定义
允许一个对象在其内部状态改变时改变它的行为。又称为状态对象模式,是一种对象行为型模式。
用于解决系统中复杂对象的状态装换以及不同状态下行为的封装问题。
角色组成
Context(环境类) | 有多种状态的对象 维护一个抽象状态类的实例,便于切换状态 |
State(抽象状态类) | 声明不同状态公共方法接口 |
ConcreteState(具体状态类) |
将对象的不同状态封装到不同的状态类中独立出来,在环境类中对状态转换代码进行集中管理
应用实例
//动画控制类:环境类
class AnimationController
{
//维持一个抽象状态类的引用
private AnimState animState;
//属性值,该属性值的变换会导致对象状态的变化
private int Speed;
public void SetSpeed(int speed)
{
Speed = speed;
Console.WriteLine("我输入了:"+Speed);
ChangeState();
}
//切换状态的业务方法
public void ChangeState()
{
if (Speed <= 0)
{
animState = new IdleState();
}
else if(Speed > 0 && Speed < 5){
animState = new WalkState();
}
else
{
animState = new RunState();
}
animState.ShowAnim();
}
}
//抽象状态类
abstract class AnimState
{
public abstract void ShowAnim();
}
//角色空闲状态
class IdleState:AnimState
{
public override void ShowAnim()
{
Console.WriteLine("展示默认角色动画");
}
}
//角色行走状态
class WalkState : AnimState
{
public override void ShowAnim()
{
Console.WriteLine("展示角色行走动画");
}
}
//角色奔跑状态
class RunState : AnimState
{
public override void ShowAnim()
{
Console.WriteLine("展示角色奔跑动画");
}
}
优缺点
缺点:状态模式对开闭原则的支持不太友好,增加新的状态类需要修改负责状态转换的源代码
适用环境
当系统中的某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同
中介者模式
定义
1、一个对象来封装一系列对象的交互。中介者模式使各对象之间不需要显式地相互引用,从而使其耦合松散,而且让你可以独立地改变它们之间的交互。
2、又称为调停模式,是一种对象行为型模式。是迪米特法则的一个典型应用。
3、在对象之间存在复杂交互关系时,通过引入中介者,将原本对象之间的两两交互转化为每个对象与中介者之间的交互,中介者可以对对象之间的通信进行控制与协调,降低了原有系统的耦合度,使得系统更加灵活,也更易于扩展。
4、如果在一个系统中对象之间存在多对多的相互关系,可以将对象之间的一些交互行为从各个对象中分离出来,集中封装在一个中介者对象中,并由该中介者进行同一协调,这样对象之间多对多的复杂关系就转化为相对简单的一对多关系。
5、中介者模式将一个网状的系统结构变成一个以中介者对象为中心的星形结构。
角色组成
Mediator(抽象中介者) | 定义一个接口,该接口用于与各同事对象之间进行通信 |
ConcreteMediator(具体中介者) | 维持对各个同事对象的引用 协调各个同事对象来实现协作行为 |
Colleague(抽象同事类) | 维持一个对抽象中介者类的引用,通过该引用与中介者通信 |
ConcreteColleague(具体同事类) |
abstract class Mediator
{
//用于存储同事对象
protected List<Colleague> colleagues = new List<Colleague>();
//注册方法,用于增加同事对象
public void Register(Colleague colleague)
{
colleagues.Add(colleague);
}
public abstract void Operation();
}
//抽象同事类
abstract class Colleague
{
//维持一个抽象中介者的引用,以便与具体中介者进行通信
protected Mediator mediator;
public Colleague(Mediator mediator)
{
this.mediator = mediator;
}
//依赖方法,与中介者进行通信
public void TalkWithMediator()
{
}
//具体同事类共有方法,业务逻辑方法
public abstract void Method();
}
//具体中介者
class ConcreteMediator : Mediator
{
public override void Operation()
{
}
}
//具体同事类
class ConcreteColleague : Colleague
{
public ConcreteColleague(Mediator mediator):base(mediator)
{
}
public override void Method()
{
}
}
应用实例
enum EventKey
{
Order,//点餐
EatFood,//吃饭
Pay,//结账
MakeFood,//制作食物
FinishFood,//完成美食
GetMoney,//收钱
CheckMoney,//清点金额
}
//抽象中介者
abstract class Mediator
{
//用于存储同事对象
protected Dictionary<string, Colleague> colleagues = new Dictionary<string, Colleague>();
//注册方法,用于增加同事对象
public void Register(Colleague colleague)
{
colleagues.Add(colleague.name, colleague);
}
public Colleague GetColleague(string name)
{
return colleagues[name];
}
public abstract void Operation(EventKey keyword, string requesterName, string responserName);
}
//抽象同事类
abstract class Colleague
{
public string name;
//维持一个抽象中介者的引用,以便与具体中介者进行通信
protected Mediator mediator;
public Colleague(string name, Mediator mediator)
{
this.name = name;
this.mediator = mediator;
}
//依赖方法,与中介者进行通信
public void TalkWithMediator(EventKey keyword, string requesterName, string responserName)
{
mediator.Operation(keyword, requesterName, responserName);
}
//具体同事类共有方法,业务逻辑方法
public abstract void Method();
}
//具体中介者
class Waiter : Mediator
{
public override void Operation(EventKey keyword, string requesterName, string responserName)
{
if(keyword == EventKey.Order)
{
var requester = (Client)GetColleague(requesterName);
var responser = (Chef)GetColleague(responserName);
requester.OrderFood();
responser.MakeFood();
}
else if(keyword == EventKey.Pay)
{
var requester = (Client)GetColleague(requesterName);
var responser = (Cashier)GetColleague(responserName);
requester.Pay();
responser.GetMoney();
responser.CheckMoney();
}
else if (keyword == EventKey.FinishFood)
{
var requester = (Chef)GetColleague(requesterName);
var responser = (Client)GetColleague(responserName);
requester.FinishFood();
responser.EatFood();
}
}
}
//顾客:具体同事类
class Client : Colleague
{
public Client(string name, Mediator mediator) : base(name, mediator)
{
}
public override void Method()
{
}
public void OrderFood()
{
Console.WriteLine("点餐");
}
public void EatFood()
{
Console.WriteLine("享受美食");
}
public void Pay()
{
Console.WriteLine("结账");
}
}
//厨师:具体同事类
class Chef : Colleague
{
public Chef(string name, Mediator mediator) : base(name, mediator)
{
}
public override void Method()
{
}
public void MakeFood()
{
Console.WriteLine("开始制作美食!");
}
public void FinishFood()
{
Console.WriteLine("制作美食完成!");
}
}
//厨师:具体同事类
class Cashier : Colleague
{
public Cashier(string name, Mediator mediator) : base(name, mediator)
{
}
public override void Method()
{
}
//收钱
public void GetMoney()
{
Console.WriteLine("已收到钱款!");
}
//完成清算
public void CheckMoney()
{
Console.WriteLine("钱款已收到,没有任何问题!");
}
}
//实例化中介者
Waiter waiter = new Waiter();
//实例化具体同事对象,并注入中介者
Colleague client = new Client("cliet",waiter);
Colleague chef = new Chef("chef",waiter);
Colleague cashier = new Cashier("cashier",waiter);
//注册具体同事对象
waiter.Register(client);
waiter.Register(chef);
waiter.Register(cashier);
client.TalkWithMediator(EventKey.Order, client.name, chef.name);
chef.TalkWithMediator(EventKey.FinishFood,chef.name,client.name);
client.TalkWithMediator(EventKey.Pay,client.name, cashier.name);
优缺点
优点
将各同事对象进行解耦,降低系统耦合度
新增中介者和同事类都比较方便,更好的符合开闭原则
缺点
具体中介者类中包含了大量的同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。
职责链模式
定义
避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。又称为责任链模式
角色组成
Handler(抽象处理者) | 一般设计为抽象类 定义处理请求的接口 保存下一处理者的引用,方便进行传递 |
ConcreteHandler(具体处理者) |
//抽象处理者类
abstract class Handler
{
//维持对下一处理者的引用
protected Handler successor;
//设置下一处理者,连接职责链
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(string request);
}
//具体处理者类
class ConcreteHandler : Handler
{
public override void HandleRequest(string request)
{
if (request == "OK")
{
//处理请求
}
else
{
this.successor.HandleRequest(request);
}
}
}
职责链模式不负责创建职责链,通常由客户端或者其他类完成
应用实例
//请求类
class PurchaseRequest
{
public int amount;
public PurchaseRequest(int amount)
{
this.amount = amount;
}
}
//审批者类:抽象处理者类
abstract class Approver
{
//维持对下一处理者的引用
protected Approver approver;
protected string name;
public Approver(string name)
{
this.name = name;
}
//设置下一处理者,连接职责链
public void SetApprover(Approver approver)
{
this.approver = approver;
}
public abstract void ProcessRequest(PurchaseRequest request);
}
//主任审批类:具体处理者类
class Director : Approver
{
public Director(string name) : base(name)
{
}
public override void ProcessRequest(PurchaseRequest request)
{
if (request.amount < 50000)
{
Console.WriteLine($"{this.name}主任处理了该账单!");
}
else
{
this.approver.ProcessRequest(request);
}
}
}
//副董事长审批类:具体处理者类
class VicePresident : Approver
{
public VicePresident(string name) : base(name)
{
}
public override void ProcessRequest(PurchaseRequest request)
{
if (request.amount >= 50000 && request.amount < 100000)
{
Console.WriteLine($"{this.name}副董事长处理了该账单!");
}
else
{
this.approver.ProcessRequest(request);
}
}
}
//董事长审批类:具体处理者类
class President : Approver
{
public President(string name) : base(name)
{
}
public override void ProcessRequest(PurchaseRequest request)
{
if (request.amount >= 100000 && request.amount < 500000)
{
Console.WriteLine($"{this.name}董事长处理了该账单!");
}
else
{
this.approver.ProcessRequest(request);
}
}
}
//董事会审批类:具体处理者类
class Congress : Approver
{
public Congress(string name) : base(name)
{
}
public override void ProcessRequest(PurchaseRequest request)
{
if (request.amount >= 500000)
{
Console.WriteLine($"召开董事会处理了该账单!");
}
else
{
this.approver.ProcessRequest(request);
}
}
}
PurchaseRequest request = new PurchaseRequest(2300000);
Approver approver1 = new Director("小明");
Approver approver2 = new VicePresident("小红");
Approver approver3 = new President("小刚");
Approver approver4 = new Congress("小丁");
approver1.SetApprover(approver2);
approver2.SetApprover(approver3);
approver3.SetApprover(approver4);
approver1.ProcessRequest(request);
分类
纯的职责链模式:要么承担全部责任,要么将责任推给下家。不能出现某个请求未被任何处理者处理的情况。
不纯的职责链模式:允许某个请求被一个处理者部分处理或者全部处理后继续向下传递。一个请求可以最终不被任何处理者处理。
优缺点
优点:实现了请求者和处理者的解耦
增加新的处理者无需修改原有系统的代码,只需要在客户端新建链即可,符合开闭原则
适用环境
遇到有多个对象可以处理同一个请求时可以应用职责链模式。
访问者模式
定义
1、表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
2、是一种对象行为型模式,它为操作存储不同类型元素的对象结构提供了一种解决方案,用户可以对不同类型的元素施加施加不同的操作。
3、包含访问者和被访问者两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。
4、由于访问者模式使用条件较为苛刻,本身结构也较为复杂,所以实际应用中的使用频率不是特别高。
角色组成
Visitor(抽象访问者) | 为每一个具体元素声明一个访问操作 |
ConcreteVisitor(具体访问者) | |
Element(抽象元素) | 声明一个Accept(Visitor visitor)方法,用于接受访问者访问 |
ConcreteElement(具体元素) | |
ObjectStructure(对象结构) | 一个元素的集合,用于存放元素的对象,并且提供了遍历内部元素的方法。 |
应用实例
//部门类:抽象访问类
abstract class Department
{
//声明一组重载的访问方法,用于访问不同类型的具体元素
public abstract void Visit(FulltimeEmployee employee);
public abstract void Visit(ParttimeEmployee employee);
}
//财务部类:具体访问类
class FADepartment : Department
{
//访问全职员工
public override void Visit(FulltimeEmployee employee)
{
Console.WriteLine($"正式员工[{employee.name}]本月工资为{employee.productCount * 100!}");
}
//访问兼职员工
public override void Visit(ParttimeEmployee employee)
{
Console.WriteLine($"正式员工[{employee.name}]本月工资为{employee.productCount * 80!}");
}
}
//人力资源部类:具体访问类
class HRDepartment : Department
{
//访问全职员工
public override void Visit(FulltimeEmployee employee)
{
Console.WriteLine($"正式员工[{employee.name}]本月工作天数为{employee.workTime!}");
}
//访问兼职员工
public override void Visit(ParttimeEmployee employee)
{
Console.WriteLine($"正式员工[{employee.name}]本月工作天数为{employee.workTime!}");
}
}
//员工类:抽象元素类
abstract class Employee
{
//接受一个抽象访问者访问
public abstract void Accept(Department handler);
}
//全职员工类:具体元素类
class FulltimeEmployee : Employee
{
public string name;//员工名称
public int productCount;//生产产品数量
public int workTime;//工作时间
public FulltimeEmployee(string name, int productCount, int workTime)
{
this.name = name;
this.productCount = productCount;
this.workTime = workTime;
}
public override void Accept(Department handler)
{
handler.Visit(this);
}
}
//全职员工类:具体元素类
class ParttimeEmployee : Employee
{
public string name;//员工名称
public int productCount;//生产产品数量
public int workTime;//工作时间
public ParttimeEmployee(string name, int productCount, int workTime)
{
this.name = name;
this.productCount = productCount;
this.workTime = workTime;
}
public override void Accept(Department handler)
{
handler.Visit(this);
}
}
//抽象结构
class EmplyeeList
{
//定义一个集合用于存储员工对象
private List<Employee> employees;
public EmplyeeList()
{
employees = new List<Employee>();
}
public void AddEmployee(Employee e)
{
employees.Add(e);
}
public void Accept(Department handler)
{
foreach (Employee e in employees)
{
e.Accept(handler);
}
}
}
EmplyeeList emplyeeList = new EmplyeeList();
Employee employee1 = new FulltimeEmployee("小红", 100, 20);
Employee employee2 = new FulltimeEmployee("小明", 120, 23);
Employee employee3 = new FulltimeEmployee("小刚", 80, 16);
Employee employee4 = new ParttimeEmployee("小绿", 110, 18);
Employee employee5 = new ParttimeEmployee("小果", 108, 20);
emplyeeList.AddEmployee(employee1);
emplyeeList.AddEmployee(employee2);
emplyeeList.AddEmployee(employee3);
emplyeeList.AddEmployee(employee4);
emplyeeList.AddEmployee(employee5);
Department department1 = new FADepartment();
Department department2 = new HRDepartment();
emplyeeList.Accept(department1);
emplyeeList.Accept(department2);
优缺点
访问者模式与抽象工厂模式类似,对开闭原则的支持具有倾斜性:
如果新增访问者,无须修改源代码,符合开闭原则
如果新增一种具体元素,则需要修改源代码,违背了开闭原则
缺点:破坏封装,元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问
适用环境
当系统中存在一个较为复杂的对象结构,且不同访问者对其所采取的操作也不相同时。
一个对象结构包含多个类型的对象,不同类型的对象可以有不同的访问操作。 ··
迭代器模式
1、提供一种方法顺序访问一个聚合对象中的各个元素,且不用暴露该对象的内部表示。又称为游标模式,是一种对象行为型模式。
2、很多编程语言的类库都已经实现了迭代器模式,因此在实际开发时直接使用语言已经定义好的迭代器即可。
3、用于遍历一个集合中所有的元素
备忘录模式
1、在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态·,这样就可以在以后将对象恢复到原先保存的状态。是一种对象行为型模式,又称为标记模式。
2、备忘录模式提供一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。
解释器模式
1、给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
2、为自定义语言的设计和实现提供了一种解决方案。主要用于解释语言和表达式
3、使用频率不高但学习难度较大