文章目录
- 一、七大原则
- 二、二十三种设计模式
- 1、创建型模式
- 2、结构型模式
- 3、行为型模式
- 3.1、模板方法模式(Template Method Pattern)
- 3.2、命令模式(Command Pattern)
- 3.3、访问者模式(Vistor Pattern)
- 3.4、迭代器模式(Iterator Pattern)
- 3.5、观察者模式(Observer Pattern)
- 3.6、中介者模式(Mediator Pattern)
- 3.7、备忘录模式(Memento Pattern)
- 3.8、解释器模式(Interpreter Pattern)
- 3.9、状态模式(State Pattern)
- 3.10、策略模式(Stragety Pattern)
- 3.11、责任链模式(Chain of Responsibility Pattern)
- 总结
最近学习了设计模式,把一些知识做个汇总记录,方便查看
一、七大原则
1、单一职责原则(SRP)
对类来说,一个类应该只负责一项职责
- 好处:维护项目、修改代码时,不会影响其他类的功能
2、接口隔离原则(ISP)
一个类对另一个类的依赖应该建立在最小的接口上
3、依赖倒转原则(DIP)
抽象不应该依赖于细节,细节应该依赖于抽象,也就是提出的 “面向接口编程,而不是面向实现编程”
4、里氏替换原则(LSP)
子类型必须能够替换掉它们的父类型;
- 继承时,在子类中尽量不要重写父类的方法
5、开闭原则(OCP)
一个软件实体(指的类、函数、模块等)应该对扩展开放,对修改关闭,用抽象构建框架,用实现扩展细节
- 为了实现,在不修改原来代码的前提下可以新增功能
6、合成复用原则(CRP)
尽量使用合成/聚合的方式,而不是使用继承
7、迪米特法则(Law of Demeter)
一个对象应当对其他对象有尽可能少的了解
- 原因:类与类关系越密切,耦合度越大(类关系密切时,当你修改一部分代码时可能影响其他的功能)
总结:实现高内聚、低耦合,使软件有更好的维护性、扩展性(方便增加新功能)、重用性(相同功能的代码,不用多次编写)和灵活性
二、二十三种设计模式
1、创建型模式
提供了创建对象的机制, 能够提升已有代码的灵活性和可复用性
1.1、单例模式(Singleton Pattern)
保证一个类仅有一个实例,并提供一个该实例的全局访问点
-
原理类图
-
使用场景
比如说我们在系统运行时候,就需要加载一些配置和属性,这些配置和属性是一定存在了,又是公共的,同时需要在整个生命周期中都存在,所以只需要一份就行,这个时候如果需要我再需要的时候new一个,再给他分配值,显然是浪费内存并且再赋值没什么意义,所以这个时候我们就需要单例模式
1.1.1、饿汉式(静态常量)(推荐单线程时使用)
/// <summary>
/// 单例模式--饿汉式(静态常量)(推荐单线程时使用)
/// 好处:多线程异步调用时,每次会new一个对象(避免线程同步问题)
/// 坏处:每次new一个对象,会造成内存的浪费
/// </summary>
class Singleton
{
//私有构造函数,使之不能实例化(不能new)
private Singleton()
{
}
//创建私有只读静态类对象
private readonly static Singleton singleton = new Singleton();
//提供公共静态方法,获取类对象
public static Singleton GetInstance()
{
return singleton;
}
}
//实现
static void Main(string[] args)
{
//1.1:单例模式--饿汉式(静态常量)(推荐单线程时使用)
Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();
Console.WriteLine("1.1:单例模式--饿汉式(静态常量)");
Console.WriteLine("singleton1的哈希码:" + singleton1.GetHashCode());
Console.WriteLine("singleton2的哈希码:" + singleton2.GetHashCode());
Console.ReadKey();
}
1.1.2、懒汉式(线程不安全)(不要使用)
/// <summary>
/// 单例模式--懒汉式(线程不安全) (不要使用)
/// 好处:避免了内存浪费(使用时才创建)
/// 坏处:只能单线程使用(多线程时,第一个还没来得及new,第二个可能判断为空,就会创建两个对象)
/// </summary>
class Singleton
{
private Singleton() { }
private static Singleton singleton;
//懒汉式:需要时才创建(当使用该方法时,才创建)
public static Singleton GetInstance()
{
if (singleton == null)
{
singleton = new Singleton();
}
return singleton;
}
}
//实现
static void Main(string[] args)
{
//1.2:单例模式--懒汉式(线程不安全)(不要使用)
Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();
Console.WriteLine("1.2:单例模式--懒汉式(线程不安全)(不要使用)");
Console.WriteLine("singleton1的哈希码:" + singleton1.GetHashCode());
Console.WriteLine("singleton2的哈希码:" + singleton2.GetHashCode());
Console.ReadKey();
}
1.1.3、懒汉式(线程安全)(不推荐)
/// <summary>
/// 单例模式--懒汉式(线程安全) (不推荐)
/// 好处:避免了内存浪费(使用时才创建)并且解决线程不安全问题
/// 坏处:每次调用同步,效率太低
/// </summary>
class Singleton
{
private static Singleton singleton;
private static readonly object locker = new object();
private Singleton() { }
/// <summary>
/// 将懒汉式线程-lock(保证加锁的线程只有在执行完成后才能执行其他线程)
/// </summary>
/// <returns></returns>
public static Singleton GetInstance()
{
lock (locker)
{
if (singleton == null)
{
singleton = new Singleton();
}
return singleton;
}
}
}
//实现
static void Main(string[] args)
{
//1.3:单例模式--懒汉式(线程安全)(不推荐)
Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();
Console.WriteLine("1.3:单例模式--懒汉式(线程安全)(不推荐)");
Console.WriteLine("singleton1的哈希码:" + singleton1.GetHashCode());
Console.WriteLine("singleton2的哈希码:" + singleton2.GetHashCode());
Console.ReadKey();
}
1.1.4、双重检查(推荐)
/// <summary>
/// 单例模式--双重检查(推荐)
/// 好处:解决懒汉式的线程不安全问题(lock),同时解决同步效率问题(volatile)
/// 坏处:
/// </summary>
class Singleton
{
//volatile 关键字可以将对象立即更新至主存
//作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.(防止编译器对代码进行优化)
//比如如下程序:
//XBYTE[2]=0x55;
//XBYTE[2]=0x56;
//XBYTE[2]=0x57;
//XBYTE[2]=0x58;
//对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,
//但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。
//如果键入volatile,则编译器会逐一的进行编译并产生相应的机器代码(产生四条代码).
private static volatile Singleton singleton;
private static readonly object locker = new object();
private Singleton() { }
public static Singleton GetInstance()
{
if (singleton == null)
{
lock (locker)
{
if (singleton == null)
{
singleton = new Singleton();
}
}
}
return singleton;
}
}
//实现
static void Main(string[] args)
{
//1.4:单例模式--双重检查(推荐)
Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();
Console.WriteLine("1.4:单例模式--双重检查(推荐)");
Console.WriteLine("singleton1的哈希码:" + singleton1.GetHashCode());
Console.WriteLine("singleton2的哈希码:" + singleton2.GetHashCode());
Console.ReadKey();
}
1.1.5、静态内部类(推荐-代码量比双重检查要少)
/// <summary>
/// 单例模式--静态内部类(推荐-代码量比双重检查要少)
/// 好处:解决懒汉式的线程不安全问题,同时解决同步效率问题:因为类装载时保证线程安全
/// 坏处:
/// </summary>
class Singleton
{
private Singleton() { }
private static class SingletonInstance
{
public static Singleton singleton = new Singleton();
}
public static Singleton GetInstance()
{
return SingletonInstance.singleton;
}
}
//实现
static void Main(string[] args)
{
//1.5:单例模式--静态内部类(推荐-代码量比双重检查要少)
Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();
Console.WriteLine("1.5:单例模式--静态内部类(推荐-代码量比双重检查要少)");
Console.WriteLine("singleton1的哈希码:" + singleton1.GetHashCode());
Console.WriteLine("singleton2的哈希码:" + singleton2.GetHashCode());
Console.ReadKey();
}
1.1.6、枚举(推荐)
public enum Singleton
{
instance,
}
//实现
static void Main(string[] args)
{
//1.6:单例模式--枚举(推荐)
Singleton singleton1 = Singleton.instance;
Singleton singleton2 = Singleton.instance;
Console.WriteLine("1.6:单例模式--枚举(推荐)");
Console.WriteLine("singleton的哈希码:" + singleton1.GetHashCode());
Console.WriteLine("singleton1的哈希码:" + singleton2.GetHashCode());
Console.ReadKey();
}
1.2、工厂方法模式(Factory Pattern)
定义一个创建对象的工厂接口,由其子类决定要实例化的类,将实际创建工作推迟到子类中。
- 原理类图
- 项目代码
披萨的项目(严格来说是简单工厂模式):
1、披萨种类较多(榴莲、菠萝等)
2、制作流程一致(准备原材料、烘烤、打包)
3、完成披萨订购
使用工厂方法模式优点:当客户需要新增披萨种类时,客户端代码不需要做较大改变,并且新增时不会影响原先代码,符合ocp原则。
/// <summary>
/// 披萨类
/// </summary>
abstract class Pizza
{
/// <summary>
/// 准备原材料
/// </summary>
public abstract void Prepare();
/// <summary>
/// 烘烤
/// </summary>
public abstract void Bake();
/// <summary>
/// 打包
/// </summary>
public abstract void Pack();
}
/// <summary>
/// 榴莲披萨
/// </summary>
class DurianPizza : Pizza
{
public override void Bake()
{
Console.WriteLine("榴莲披萨已烘烤");
}
public override void Pack()
{
Console.WriteLine("榴莲披萨已打包");
}
public override void Prepare()
{
Console.WriteLine("榴莲披萨已准备原材料");
}
}
/// <summary>
/// 菠萝披萨
/// </summary>
class PineapplePizza : Pizza
{
public override void Bake()
{
Console.WriteLine("菠萝披萨已烘烤");
}
public override void Pack()
{
Console.WriteLine("菠萝披萨已打包");
}
public override void Prepare()
{
Console.WriteLine("菠萝披萨已准备原材料");
}
}
/// <summary>
/// 工厂
/// </summary>
class Factory
{
/// <summary>
/// 创建静态披萨
/// </summary>
/// <param name="pizzaType"></param>
/// <returns></returns>
public static Pizza CreatePizza(string pizzaType)
{
Pizza pizza = null;
Console.WriteLine("使用静态工厂模式");
switch(pizzaType)
{
case "榴莲":
pizza = new DurianPizza();
break;
case "菠萝":
pizza = new PineapplePizza();
break;
//新增披萨种类
//case "新":
// pizza = new NewPizza();
// break;
}
return pizza;
}
}
/// <summary>
/// 订购(客户端)
/// </summary>
public class Order
{
public Order()
{
Console.WriteLine("请输入需要订购的披萨");
do
{
string pizzaType = Console.ReadLine();//接受控制台输入的一个字符串
Pizza pizza = Factory.CreatePizza(pizzaType);
if (pizza != null)
{
pizza.Prepare();
pizza.Bake();
pizza.Pack();
}
else
{
Console.WriteLine("订购披萨失败");
}
} while (true);
}
}
//实现
static void Main(string[] args)
{
//2:工厂方法模式
new Order();
Console.ReadKey();
}
1.3、抽象工厂模式(Abstract Pattern)(对简单工厂模式进行改进)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 原理类图
- 项目代码
披萨连锁店的项目(产品簇):
1、披萨连锁店的产品:披萨、奶茶
2、不同地区:广州、江西(不同地区的口味不同)
使用抽象工厂方法模式优点:当客户需要新增不同地区的产品时,客户端代码不需要做较大改变,并且新增时不会影响原先代码,符合ocp原则。
/// <summary>
/// 披萨
/// </summary>
abstract class Pizza
{
/// <summary>
/// 生产披萨
/// </summary>
public abstract void CreatePizza();
}
/// <summary>
/// 奶茶
/// </summary>
abstract class MilkyTea
{
/// <summary>
/// 生产奶茶
/// </summary>
public abstract void CreateMilkyTea();
}
/// <summary>
/// 广州口味披萨
/// </summary>
class GuangzhouPizza : Pizza
{
public override void CreatePizza()
{
Console.WriteLine("广州口味披萨");
}
}
/// <summary>
/// 江西口味披萨
/// </summary>
class JiangXiPizza : Pizza
{
public override void CreatePizza()
{
Console.WriteLine("江西口味披萨");
}
}
/// <summary>
/// 广州口味奶茶
/// </summary>
class GuangzhouMilkyTea : MilkyTea
{
public override void CreateMilkyTea()
{
Console.WriteLine("广州口味奶茶");
}
}
/// <summary>
/// 江西口味奶茶
/// </summary>
class JiangXiMilkyTea : MilkyTea
{
public override void CreateMilkyTea()
{
Console.WriteLine("江西口味奶茶");
}
}
/// <summary>
/// 抽象工厂接口
/// </summary>
interface IAbstractFactoryable
{
/// <summary>
/// 生产披萨
/// </summary>
/// <returns></returns>
Pizza CreatePizza();
/// <summary>
/// 生产奶茶
/// </summary>
/// <returns></returns>
MilkyTea CreateMilkyTea();
}
/// <summary>
/// 江西的工厂
/// </summary>
class JiangXiFactory : IAbstractFactoryable
{
public MilkyTea CreateMilkyTea()
{
return new JiangXiMilkyTea();
}
public Pizza CreatePizza()
{
return new JiangXiPizza();
}
}
/// <summary>
/// 广州工厂
/// </summary>
class GuangzhouFactory : IAbstractFactoryable
{
public MilkyTea CreateMilkyTea()
{
return new GuangzhouMilkyTea();
}
public Pizza CreatePizza()
{
return new GuangzhouPizza();
}
}
//实现
static void Main(string[] args)
{
//3:抽象工厂模式
//江西工厂
IAbstractFactoryable abstractFactoryable1 = new JiangXiFactory();
abstractFactoryable1.CreatePizza().CreatePizza();
abstractFactoryable1.CreateMilkyTea().CreateMilkyTea();
//广州工厂
IAbstractFactoryable abstractFactoryable2 = new GuangzhouFactory();
abstractFactoryable2.CreatePizza().CreatePizza();
abstractFactoryable2.CreateMilkyTea().CreateMilkyTea();
Console.ReadKey();
}
1.4、原型模式(Prototype Pattern)
使你能够复制对象, 甚至是复杂对象, 而又无需使代码依赖它们所属的类。
- 原理类图
- 项目代码
class Person
{
private string name;
private int age;
private IDCard iDCard;
public string Name { get => name; set => name = value; }
public int Age { get => age; set => age = value; }
internal IDCard IDCard { get => iDCard; set => iDCard = value; }
/// <summary>
/// 浅拷贝
/// 拷贝值类型时,在栈空间中复制一个新的内存地址
/// 拷贝引用类型时,拷贝的是指向堆是上的一个地址
/// </summary>
/// <returns></returns>
public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
}
/// <summary>
/// 深拷贝(也可使用序列化和反序列化、反射)
/// 拷贝值类型时,在栈空间中复制一个新的内存地址
/// 拷贝引用类型时,拷贝的是新的堆内存地址
/// </summary>
/// <returns></returns>
public Person DeepCopy()
{
Person clone = (Person)this.MemberwiseClone();
clone.IDCard = new IDCard(IDCard.Info);
clone.Name = String.Copy(Name);
return clone;
}
public Person(string name ,int age, IDCard iDCard)
{
Name = name;
Age = age;
IDCard = iDCard;
}
/// <summary>
/// 为了方便显示重写ToString方法
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format("name:{0}——age:{1}——iDCard的哈希码:{2}", name, age, iDCard.GetHashCode());
}
}
/// <summary>
/// 身份证
/// </summary>
class IDCard
{
private string info;
public IDCard(string info)
{
this.Info = info;
}
public string Info { get => info; set => info = value; }
}
//实现
static void Main(string[] args)
{
//4:原型模式
Person person = new Person("周",12,new IDCard("这是我的身份证信息"));
//浅拷贝
Person shallowPerson = person.ShallowCopy();
Console.WriteLine("原对象:" + person.ToString());
Console.WriteLine("浅拷贝:" + shallowPerson.ToString());
Console.WriteLine("----------------------------------------------------");
//深拷贝
Person deepPerson = person.DeepCopy();
Console.WriteLine("原对象:" + person.ToString());
Console.WriteLine("深拷贝:" + deepPerson.ToString());
Console.ReadKey();
}
1.5、建造者模式(Builder Pattern)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 原理类图
- 项目代码
建造房子的项目:
1、建造房子过程:建造地基、建造墙壁、建造房顶
2、房子类型:通用型房子、高楼
3、当你为用户时,你希望对包工头(建造者)说建造两栋房子(一栋通用形、一栋高楼),让包工头去调配具体建造过程,而不会自己去指挥房子建造过程。
/// <summary>
/// 房子
/// </summary>
public abstract class House
{
/// <summary>
/// 建造地基
/// </summary>
public abstract void BulidFoundation();
/// <summary>
/// 建造墙壁
/// </summary>
public abstract void BulidWall();
/// <summary>
/// 建筑房顶
/// </summary>
public abstract void BulidRoof();
}
/// <summary>
/// 通用型房子
/// </summary>
class CommonHouse : House
{
public override void BulidFoundation()
{
Console.WriteLine("建造通用型房子地基");
}
public override void BulidRoof()
{
Console.WriteLine("建造通用型房子房顶");
}
public override void BulidWall()
{
Console.WriteLine("建造通用型房子墙壁");
}
}
/// <summary>
/// 高楼
/// </summary>
class HighHouse : House
{
public override void BulidFoundation()
{
Console.WriteLine("建造高楼地基");
}
public override void BulidRoof()
{
Console.WriteLine("建造高楼房顶");
}
public override void BulidWall()
{
Console.WriteLine("建造高楼墙壁");
}
}
/// <summary>
/// 指挥者(建造者)
/// </summary>
public class Commander
{
/// <summary>
/// 由指挥者去调配建造房子
/// </summary>
/// <param name="house"></param>
public void Bulid(House house)
{
house.BulidFoundation();
house.BulidWall();
house.BulidRoof();
}
}
//实现
static void Main(string[] args)
{
//5:建造者模式
//客户找到指挥者说要建造两栋房子,一栋通用形、一栋高楼
//创建指挥者
Commander commander = new Commander();
//建造通用形房子
commander.Bulid(new CommonHouse());
//建造高楼
commander.Bulid(new HighHouse());
Console.ReadKey();
}
2、结构型模式
将对象和类组装成较大的结构, 并同时保持结构的灵活和高效
2.1、适配器模式(Adapter Pattern)
使接口不兼容的对象能够相互合作,将某个类的接口转换为客户端期望的另一个接口
- 主要目的:兼容性
- 使用场景:旅行中遇到插座(欧标),可以买个多功能转换插座(适配器)就可以使用国标的产品了
- 原理类图
2.1.1、类适配器模式
- 项目代码
电压适配器项目(c#因为是单继承,一定的使用到接口):
1、适配器将220V转为5V接口
/// <summary>
/// 220伏电压
/// </summary>
public class Voltage220V
{
public int Output220V()
{
int voltage = 220;
Console.WriteLine(string.Format("输出电压为{0}V", voltage));
return voltage;
}
}
/// <summary>
/// 5伏电压接口
/// </summary>
public interface IVoltage5V {
int Output5V();
}
/// <summary>
/// 电压适配器:电压将220V电压转换为5V
/// </summary>
public class VoltageAdapter : Voltage220V, IVoltage5V
{
public int Output5V()
{
int voltage = Output220V() / 44;
Console.WriteLine(string.Format("输出电压转化为{0}V", voltage));
return voltage;
}
}
//实现
static void Main(string[] args)
{
//1.1:类适配器模式
VoltageAdapter voltageAdapter = new VoltageAdapter();
//缺点可以使用220伏电压的方法
voltageAdapter.Output220V();
Console.WriteLine("----------------------------------------------------");
voltageAdapter.Output5V();
Console.ReadKey();
}
2.1.2、对象适配器模式
将类适配器中继承类私有化,是客户端不能调用
/// <summary>
/// 220伏电压
/// </summary>
public class Voltage220V
{
public int Output220V()
{
int voltage = 220;
Console.WriteLine(string.Format("输出电压为{0}V", voltage));
return voltage;
}
}
/// <summary>
/// 5伏电压接口
/// </summary>
public interface IVoltage5V {
int Output5V();
}
/// <summary>
/// 电压适配器:电压将220V电压转换为5V
/// </summary>
public class VoltageAdapter : IVoltage5V
{
private readonly Voltage220V voltage220V;
public VoltageAdapter(Voltage220V voltage220V)
{
this.voltage220V = voltage220V;
}
public int Output5V()
{
int voltage = 0;
if (voltage220V != null)
{
voltage = voltage220V.Output220V() / 44;
Console.WriteLine(string.Format("输出电压转化为{0}V", voltage));
}
return voltage;
}
}
//实现
static void Main(string[] args)
{
//1.2:对象适配器模式
VoltageAdapter voltageAdapter = new VoltageAdapter(new Voltage220V());
voltageAdapter.Output5V();
Console.ReadKey();
}
2.2、桥接模式(Bridge Pattern)
将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构, 从而能在开发时分别使用
-
原理类图
-
项目代码
手机项目:
1、手机功能:开机、关机、打电话
2、手机种类:智能手机、非智能手机
3、手机厂商:华为、小米等(每个厂商都生产智能手机和非智能手机)
/// <summary>
/// 手机功能接口
/// </summary>
public interface IPhoneFunction
{
/// <summary>
/// 开机
/// </summary>
void open();
/// <summary>
/// 关机
/// </summary>
void close();
/// <summary>
/// 打电话
/// </summary>
void call();
}
/// <summary>
/// 华为
/// </summary>
public class HuaWei : IPhoneFunction
{
public void call()
{
Console.WriteLine("华为手机打电话");
}
public void close()
{
Console.WriteLine("华为手机关机");
}
public void open()
{
Console.WriteLine("华为手机开机");
}
}
/// <summary>
/// 小米
/// </summary>
public class XiaoMi : IPhoneFunction
{
public void call()
{
Console.WriteLine("小米手机打电话");
}
public void close()
{
Console.WriteLine("小米手机关机");
}
public void open()
{
Console.WriteLine("小米手机开机");
}
}
/// <summary>
/// 手机类
/// </summary>
public abstract class Phone
{
private readonly IPhoneFunction phoneFunction;
//通过构造器传入
public Phone(IPhoneFunction phoneFunction)
{
this.phoneFunction = phoneFunction;
}
protected void open()
{
this.phoneFunction.open();
}
protected void close()
{
this.phoneFunction.close();
}
protected void call()
{
this.phoneFunction.call();
}
}
/// <summary>
/// 智能手机
/// </summary>
public class SmartPhone : Phone
{
//构造器将参数(phoneFunction)传入父类(Phone)构造器中
public SmartPhone(IPhoneFunction phoneFunction) : base(phoneFunction)
{
Console.WriteLine("智能手机:");
}
public void Open()
{
base.open();
}
public void Close()
{
base.close();
}
public void Call()
{
base.call();
}
}
/// <summary>
/// 非智能手机
/// </summary>
public class NotSmartPhone : Phone
{
//构造器将参数(phoneFunction)传入父类(Phone)构造器中
public NotSmartPhone(IPhoneFunction phoneFunction) : base(phoneFunction)
{
Console.WriteLine("非智能手机:");
}
public void Open()
{
base.open();
}
public void Close()
{
base.close();
}
public void Call()
{
base.call();
}
}
//实现
static void Main(string[] args)
{
//2、桥接模式
//创建华为智能手机
SmartPhone smartPhone = new SmartPhone(new HuaWei());
//开机、打电话、关机
smartPhone.Open(); smartPhone.Call(); smartPhone.Close();
Console.WriteLine("----------------------------------------------------");
//创建小米非智能手机
NotSmartPhone notSmartPhone = new NotSmartPhone(new XiaoMi());
//开机、打电话、关机
notSmartPhone.Open(); notSmartPhone.Call(); notSmartPhone.Close();
Console.ReadKey();
}
2.3、装饰者模式(Decorator Pattern)
允许你通过将对象放入特殊封装对象中来为原对象增加新的行为。
- 原理类图
- 项目代码
奶茶订单项目:
1、奶茶种类:原味奶茶、苹果奶茶、柠檬奶茶
2、调料:芋圆、椰果、仙草冻,加一份要加钱
3、计算不同种类的奶茶费用:可以点原味奶茶,也可以点原味奶茶加一份芋圆、也可以点原味奶茶加两份芋圆
/// <summary>
/// 抽象类-饮料
/// </summary>
public abstract class Drink
{
private string name; //名称
private float price = 0.0f; //价格
public virtual string GetName(){
return name;
}
public void SetName(string name) {
this.name = name;
}
public float GetPrice()
{
return price;
}
public void SetPrice(float price)
{
this.price = price;
}
//计算价格
public abstract float cost();
}
/// <summary>
/// 奶茶
/// </summary>
class TeaWithMilk : Drink
{
public override float cost()
{
return base.GetPrice();
}
}
/// <summary>
/// 原味奶茶
/// </summary>
class OriginalTeaWithMilk : TeaWithMilk
{
public OriginalTeaWithMilk()
{
base.SetName("原味奶茶");
base.SetPrice(5.0f);
}
}
/// <summary>
/// 苹果奶茶
/// </summary>
class AppleTeaWithMilk : TeaWithMilk
{
public AppleTeaWithMilk()
{
base.SetName("苹果奶茶");
base.SetPrice(3.0f);
}
}
/// <summary>
/// 柠檬奶茶
/// </summary>
class LemonTeaWithMilk : TeaWithMilk
{
public LemonTeaWithMilk()
{
base.SetName("柠檬奶茶");
base.SetPrice(8.0f);
}
}
/// <summary>
/// 装饰者
/// </summary>
public class Decorator:Drink
{
private readonly Drink drink;
public Decorator(Drink drink)
{
this.drink = drink;
}
public override float cost()
{
return base.GetPrice() + drink.cost();
}
public override string GetName()
{
return base.GetName() + " " + base.GetPrice() + " && " + drink.GetName();
}
}
/// <summary>
/// 芋圆
/// </summary>
public class TaroBalls : Decorator
{
public TaroBalls(Drink drink) : base(drink)
{
base.SetName("芋圆");
base.SetPrice(1.0f);
}
}
/// <summary>
/// 椰果
/// </summary>
public class Coconut : Decorator {
public Coconut(Drink drink) : base(drink)
{
base.SetName("椰果");
base.SetPrice(0.5f);
}
}
/// <summary>
/// 仙草冻
/// </summary>
public class FairyGrassJelly : Decorator
{
public FairyGrassJelly(Drink drink) : base(drink)
{
base.SetName("仙草冻");
base.SetPrice(1.5f);
}
}
//实现
static void Main(string[] args)
{
//3、装饰者模式
//点一份原味奶茶
Drink drink = new OriginalTeaWithMilk();
Console.WriteLine(drink.GetName() + "---" + drink.cost());
//在原味奶茶里加一份椰果
drink = new Coconut(drink);
Console.WriteLine(drink.GetName() + "---" + drink.cost());
//在原味奶茶里加一份椰果在加一份芋圆
drink = new TaroBalls(drink);
Console.WriteLine(drink.GetName() + "---" + drink.cost());
Console.ReadKey();
}
2.4、组合模式(Composite Pattern)
又叫部分整体模式,将对象组合成树状结构, 并且能像使用独立对象一样使用它们
- 原理类图
- 项目代码
学校院系展示项目:
1、可动态添加移除学校、学院、院系
2、展示出学校的院系组成,一个学校有多个学院,一个学院有多个系
/// <summary>
/// 组织
/// </summary>
abstract class Organization
{
private string name;
public string Name { get => name; set => name = value; }
/// <summary>
/// 添加组织
/// </summary>
/// <param name="organization"></param>
public abstract void add(Organization organization);
/// <summary>
/// 移除组织
/// </summary>
/// <param name="organization"></param>
public abstract void remove(Organization organization);
/// <summary>
/// 展示
/// </summary>
public abstract void show();
}
/// <summary>
/// 学校
/// </summary>
class School : Organization
{
List<Organization> organizations = new List<Organization>();
public School(string name)
{
base.Name = name;
}
public override void add(Organization organization)
{
organizations.Add(organization);
}
public override void remove(Organization organization)
{
organizations.Remove(organization);
}
public override void show()
{
Console.WriteLine("------------------" + base.Name + "-------------------");
foreach (Organization item in organizations)
{
item.show();
}
}
}
/// <summary>
/// 学院
/// </summary>
class College : Organization
{
List<Organization> organizations = new List<Organization>();
public College(string name)
{
base.Name = name;
}
public override void add(Organization organization)
{
organizations.Add(organization);
}
public override void remove(Organization organization)
{
organizations.Remove(organization);
}
public override void show()
{
Console.WriteLine("------------------" + base.Name + "-------------------");
foreach (Organization item in organizations)
{
item.show();
}
}
}
/// <summary>
/// 院系
/// </summary>
class Faculty : Organization
{
public Faculty(string name)
{
base.Name = name;
}
public override void add(Organization organization)
{
throw new NotImplementedException();
}
public override void remove(Organization organization)
{
throw new NotImplementedException();
}
public override void show()
{
Console.WriteLine(base.Name);
}
}
//实现
static void Main(string[] args)
{
//4、组合模式
//创建学校
Organization organization = new School("xx大学");
//创建学院
Organization computerCollege = new College("计算机学院");
Organization environmentCollege = new College("环境学院");
//将学院加入学校
organization.add(computerCollege);
organization.add(environmentCollege);
//将院系加入学院
computerCollege.add(new Faculty("软件工程"));
computerCollege.add(new Faculty("计算机科学与技术系"));
computerCollege.add(new Faculty("电子工程系"));
environmentCollege.add(new Faculty("环境工程系"));
//显示学校
organization.show();
Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!");
//显示计算机学院
computerCollege.show();
Console.ReadKey();
}
2.5、外观模式(Facade Pattern)
为程序库、 框架或其他复杂类提供一个简单的接口
- 原理类图
- 项目代码
家庭影院项目:DVD、投影仪、屏幕、环绕立体声、爆米花机、灯光,要求完成使用家庭影院的功能,其过程为:
1、直接用遥控器:统筹各设备开关
2、开爆米花机,开始爆米花
3、放下屏幕
4、开投影仪、环绕立体声、DVD
5、调暗灯光
6、播放
7、观影结束,关闭各种设备
/// <summary>
/// DVD
/// </summary>
public class DVD
{
//单例模式-静态内部类
private DVD() { }
private static class DVDSingleton
{
public static DVD dvd = new DVD();
}
public static DVD GetDVD()
{
return DVDSingleton.dvd;
}
public void On()
{
Console.WriteLine("打开DVD");
}
public void Off()
{
Console.WriteLine("关闭DVD");
}
public void Play()
{
Console.WriteLine("播放DVD");
}
public void Pause()
{
Console.WriteLine("暂停播放DVD");
}
}
/// <summary>
/// 投影仪
/// </summary>
public class Projector
{
private Projector()
{
}
private static class ProjectorSingleton
{
public static Projector projector = new Projector();
}
public static Projector GetProjector()
{
return ProjectorSingleton.projector;
}
public void On()
{
Console.WriteLine("打开投影仪");
}
public void Off()
{
Console.WriteLine("关闭投影仪");
}
}
/// <summary>
/// 环绕立体声
/// </summary>
public class Stereo {
private Stereo()
{
}
private static class StereoSingleton {
public static Stereo stereo = new Stereo();
}
public static Stereo GetStereo()
{
return StereoSingleton.stereo;
}
public void On()
{
Console.WriteLine("打开环绕立体声");
}
public void Off()
{
Console.WriteLine("关闭环绕立体声");
}
public void Up()
{
Console.WriteLine("将声音调大");
}
public void Down()
{
Console.WriteLine("将声音调小");
}
}
/// <summary>
/// 爆米花机
/// </summary>
public class Popcorn
{
private Popcorn()
{
}
private static class PopcornSingleton
{
public static Popcorn popcorn = new Popcorn();
}
public static Popcorn GetPopcorn()
{
return PopcornSingleton.popcorn;
}
public void On()
{
Console.WriteLine("打开爆米花机");
}
public void Off()
{
Console.WriteLine("关闭爆米花机");
}
public void Pop()
{
Console.WriteLine("爆米花机正在爆米花");
}
}
/// <summary>
/// 屏幕
/// </summary>
public class Screen
{
private Screen()
{
}
private static class ScreenSingleton
{
public static Screen screen = new Screen();
}
public static Screen GetScreen()
{
return ScreenSingleton.screen;
}
public void Up()
{
Console.WriteLine("屏幕伸起");
}
public void Down()
{
Console.WriteLine("屏幕下降");
}
}
/// <summary>
/// 灯光
/// </summary>
public class Light
{
private Light()
{
}
private static class LightSingleton
{
public static Light light = new Light();
}
public static Light GetLight()
{
return LightSingleton.light;
}
public void On()
{
Console.WriteLine("打开灯光");
}
public void Off()
{
Console.WriteLine("关闭灯光");
}
public void Bright()
{
Console.WriteLine("灯光调亮");
}
public void Dark()
{
Console.WriteLine("灯光调暗");
}
}
/// <summary>
/// 外观类(家庭影院)
/// </summary>
class FacadeHomeTheater
{
private DVD dvd = DVD.GetDVD();
private Projector projector = Projector.GetProjector();
private Stereo stereo = Stereo.GetStereo();
private Popcorn popcorn = Popcorn.GetPopcorn();
private Screen screen = Screen.GetScreen();
private Light light = Light.GetLight();
/// <summary>
/// 准备工作
/// </summary>
public void Ready()
{
popcorn.On();
popcorn.Pop();
screen.Down();
projector.On();
stereo.On();
dvd.On();
light.Dark();
}
/// <summary>
/// 播放
/// </summary>
public void Play()
{
dvd.Play();
}
/// <summary>
/// 暂停
/// </summary>
public void Pause()
{
dvd.Pause();
}
/// <summary>
/// 结束
/// </summary>
public void End()
{
light.Bright();
screen.Up();
popcorn.Off();
projector.Off();
stereo.Off();
dvd.Off();
}
}
//实现
static void Main(string[] args)
{
//5、外观模式
FacadeHomeTheater facadeHomeTheater = new FacadeHomeTheater();
facadeHomeTheater.Ready();
facadeHomeTheater.Play();
facadeHomeTheater.Pause();
facadeHomeTheater.End();
Console.ReadKey();
}
2.6、享元模式(Flyweight Pattern)
摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象
- 享元:共享对象
- 使用场景:数据库连接池
- 原理类图
- 项目代码
游戏系统
1、初始需要创建很多角色
2、角色类型:战士和法师
3、每个角色用户名不一样
/// <summary>
/// 用户(外部状态)
/// </summary>
public class User
{
public User(string name) {
this.name = name;
}
private string name;
public string Name { get => name; }
}
/// <summary>
/// 角色
/// </summary>
public abstract class Role
{
//创建初始角色
public abstract void Create(User user);
}
/// <summary>
/// 角色类型(枚举)
/// </summary>
public enum RoleType
{
/// <summary>
/// 战士
/// </summary>
Warrior,
/// <summary>
/// 法师
/// </summary>
Master
}
/// <summary>
/// 具体角色
/// </summary>
public class ConcreteRole : Role
{
private readonly RoleType roleType;
public ConcreteRole(RoleType roleType)
{
this.roleType = roleType;
}
public override void Create(User user)
{
Console.WriteLine("创建人物角色__ 角色类型:" + roleType.ToString() + " 用户名:" + user.Name);
}
}
/// <summary>
/// 角色工厂
/// </summary>
public class RoleFactory
{
private Hashtable hashtable = new Hashtable();
/// <summary>
/// 创建角色类型
/// </summary>
/// <param name="roleType"></param>
/// <returns></returns>
public Role CreateConcreteRole(RoleType roleType)
{
//没有该角色类型时创建
if (!hashtable.ContainsKey(roleType))
{
hashtable.Add(roleType, new ConcreteRole(roleType));
}
return hashtable[roleType] as Role;
}
/// <summary>
/// 获取角色类型总数
/// </summary>
/// <returns></returns>
public int GetRoleCount()
{
return hashtable.Count;
}
}
//实现
static void Main(string[] args)
{
//6、享元模式
RoleFactory roleFactory = new RoleFactory();
//创建20个战士角色,用户名不同
for (int i = 0; i < 20; i++)
{
Role role = roleFactory.CreateConcreteRole(RoleType.Warrior);
role.Create(new User("小王" + i));
}
//创建20个法师角色,用户名不同
for (int i = 0; i < 20; i++)
{
Role role = roleFactory.CreateConcreteRole(RoleType.Master);
role.Create(new User("小明" + i));
}
Console.WriteLine("角色总个数为:" + roleFactory.GetRoleCount());
Console.ReadKey();
}
2.7、代理模式(Proxy Pattern)
让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。
- 原理类图
2.7.1、静态代理
- 优缺点
优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展
缺点:因为代理对象需要与目标对象实现一样的接口,一旦接口增加,代理对象和目标对象都要维护 - 项目代码
在不改变原本的代码的情况下向方法里扩充
1、原本的代码:一个人物类(Person)通过实现接口(IRunable)里的跑步方法
2、在不改变原本的代码向跑步方法里扩充(先热身、跑步、停止跑步)
public interface IRunable
{
void Run();
}
/// <summary>
/// 人物
/// </summary>
public class Person : IRunable
{
public void Run()
{
Console.WriteLine("正在跑步中");
}
}
/// <summary>
/// 代理人物
/// </summary>
public class PersonProxy : IRunable
{
private readonly Person person;
public PersonProxy(Person person)
{
this.person = person;
}
public void Run()
{
Console.WriteLine("跑步前热身中");
person.Run();
Console.WriteLine("停止跑步");
}
}
//实现
static void Main(string[] args)
{
//7.1、代理模式(静态代理)
PersonProxy personProxy = new PersonProxy(new Person());
personProxy.Run();
Console.ReadKey();
}
2.7.1、动态代理
-
优缺点
优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展,比动态代理有好的扩展性
缺点:被代理对象的方法一定的是虚方法,还需引用Castle.Core包 -
项目代码
在不改变原本的代码的情况下向方法里扩充
1、原本的代码:一个人物类(Person)含有跑步方法(虚方法)
2、在不改变原本的代码向跑步方法里扩充(先热身、跑步、停止跑步)
/// <summary>
/// 人物
/// </summary>
public class Person
{
//一定的是虚方法
public virtual void Run()
{
Console.WriteLine("正在跑步中");
}
}
/// <summary>
///创建一个拦截器并实现IInterceptor接口
/// </summary>
public class PersonIInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
//扩充方法
Console.WriteLine("跑步前热身中");
invocation.Proceed();
Console.WriteLine("停止跑步");
}
}
/// <summary>
/// 代理人物
/// </summary>
public static class PersonProxy
{
public static Person GetPersonProxy()
{
//生成代理对象
ProxyGenerator proxyGenerator = new ProxyGenerator();
Person proyLandlord = proxyGenerator.CreateClassProxy<Person>(new PersonIInterceptor());
return proyLandlord;
}
}
//实现
static void Main(string[] args)
{
//7.2、代理模式(动态代理)
Proxy.Person person = PersonProxy.GetPersonProxy();
person.Run();
Console.ReadKey();
}
3、行为型模式
负责对象间的高效沟通和职责委派
3.1、模板方法模式(Template Method Pattern)
它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤
- 原理类图
- 项目代码
制作豆浆项目
1、流程:选材–添加配料–浸泡–放入豆浆机打碎
2、通过添加不同配料,可以制作不同口味的豆浆(红枣豆浆、枸杞豆浆)
3、选材、浸泡和放入豆浆机打碎这几个步骤是不变的
/// <summary>
/// 豆浆
/// </summary>
public abstract class SoybeanMilk
{
/// <summary>
/// 选材
/// </summary>
private void Ready()
{
Console.WriteLine("选择好的黄豆");
}
/// <summary>
/// 添加配料
/// </summary>
public abstract void AddIngredients();
/// <summary>
/// 浸泡
/// </summary>
private void Soak()
{
Console.WriteLine("将黄豆浸泡");
}
/// <summary>
/// 打碎
/// </summary>
private void Smash()
{
Console.WriteLine("将所有材料放入豆浆机打碎");
}
/// <summary>
/// 制作豆浆
/// </summary>
public void Make()
{
Ready();
AddIngredients();
Soak();
Smash();
}
}
/// <summary>
/// 红枣豆浆
/// </summary>
public class RedJujubeSoybeanMilk : SoybeanMilk
{
public override void AddIngredients()
{
Console.WriteLine("添加红枣");
}
}
/// <summary>
/// 枸杞豆浆
/// </summary>
public class ChineseWolfberrySoybeanMilk : SoybeanMilk
{
public override void AddIngredients()
{
Console.WriteLine("添加枸杞");
}
}
//实现
static void Main(string[] args)
{
//1、模板方法模式
//红枣豆浆
SoybeanMilk soybeanMilk1 = new RedJujubeSoybeanMilk();
soybeanMilk1.Make();
Console.WriteLine("----------------------------------------------------");
//枸杞豆浆
SoybeanMilk soybeanMilk2 = new ChineseWolfberrySoybeanMilk();
soybeanMilk2.Make();
Console.ReadKey();
}
3.2、命令模式(Command Pattern)
将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。
- 原理类图
- 项目代码
家庭智能项目
1、对DVD、投影仪、爆米花机、灯光的开关实行控制(代码里只写了DVD)
/// <summary>
/// DVD
/// </summary>
public class DVDReceiver
{
public void On()
{
Console.WriteLine("DVD打开了");
}
public void Off()
{
Console.WriteLine("DVD关闭了");
}
}
/// <summary>
/// 命令接口
/// </summary>
public interface ICommand
{
/// <summary>
/// 执行
/// </summary>
void Execute();
/// <summary>
/// 撤销
/// </summary>
void Undo();
}
/// <summary>
/// 空命令-方便实例化
/// </summary>
public class NoCommand : ICommand
{
public void Execute()
{
throw new NotImplementedException();
}
public void Undo()
{
throw new NotImplementedException();
}
}
/// <summary>
/// DVD开命令
/// </summary>
public class DVDOnCommand : ICommand
{
DVDReceiver dVDReceiver;
public DVDOnCommand(DVDReceiver dVDReceiver)
{
this.dVDReceiver = dVDReceiver;
}
public void Execute()
{
dVDReceiver.On();
}
public void Undo()
{
dVDReceiver.Off();
}
}
/// <summary>
/// DVD关命令
/// </summary>
public class DVDOffCommand : ICommand
{
DVDReceiver dVDReceiver;
public DVDOffCommand(DVDReceiver dVDReceiver)
{
this.dVDReceiver = dVDReceiver;
}
public void Execute()
{
dVDReceiver.Off();
}
public void Undo()
{
dVDReceiver.On();
}
}
/// <summary>
/// 遥控器
/// </summary>
public class RemoteController {
//按钮命令数组
ICommand[] onCommands = new ICommand[4];
ICommand[] offCommands = new ICommand[4];
//撤销命令
ICommand undoCommand;
public RemoteController()
{
//按钮初始化
for (int i = 0; i < 4; i++)
{
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
/// <summary>
/// 给按钮设置命令
/// </summary>
/// <param name="i">索引</param>
/// <param name="onCommand">开命令</param>
/// <param name="offCommand">关命令</param>
public void SetCommand(int i, ICommand onCommand, ICommand offCommand)
{
onCommands[i] = onCommand;
offCommands[i] = offCommand;
}
/// <summary>
/// 按下开按钮
/// </summary>
/// <param name="i"></param>
public void OnButtonWasPushed(int i)
{
//执行开命令
onCommands[i].Execute();
//记录操作,方便撤销
undoCommand = onCommands[i];
}
/// <summary>
/// 按下关按钮
/// </summary>
/// <param name="i"></param>
public void OffButtonWasPushed(int i)
{
//执行开命令
offCommands[i].Execute();
//记录操作,方便撤销
undoCommand = offCommands[i];
}
/// <summary>
/// 按下撤销按钮
/// </summary>
public void UndoButtonWasPushed()
{
//执行撤销命令
undoCommand.Undo();
}
}
//实现
static void Main(string[] args)
{
//2、命令模式
//创建遥控器
RemoteController remoteController = new RemoteController();
//向遥控器里添加DVD开关命令
remoteController.SetCommand(0, new DVDOnCommand(new DVDReceiver()), new DVDOffCommand(new DVDReceiver()));
//执行开DVD
remoteController.OnButtonWasPushed(0);
//执行关DVD
remoteController.OffButtonWasPushed(0);
//执行撤销命令
remoteController.UndoButtonWasPushed();
Console.ReadKey();
}
3.3、访问者模式(Vistor Pattern)
将算法与其所作用的对象隔离开来
- 原理类图
- 项目代码
歌手海选项目
1、歌手分为男子组和女子组,成功则晋级,失败则淘汰
public abstract class Person {
private string name;
public Person(string name)
{
this.name = name;
}
public string Name { get => name;}
//接收结果
public abstract void Accept(Action action);
}
public class Man : Person
{
public Man(string name) : base(name) { }
public override void Accept(Action action)
{
action.GetManResult(this);
}
}
public class Woman : Person
{
public Woman(string name) : base(name) { }
public override void Accept(Action action)
{
action.GetWomanResult(this);
}
}
/// <summary>
/// 行为-结果
/// </summary>
public abstract class Action
{
//获取男子组结果
public abstract void GetManResult(Man man);
//获取女子组结果
public abstract void GetWomanResult(Woman woman);
}
/// <summary>
/// 成功
/// </summary>
public class Success : Action
{
public override void GetManResult(Man man)
{
Console.WriteLine("{0}在男子组中晋级成功", man.Name);
}
public override void GetWomanResult(Woman woman)
{
Console.WriteLine("{0}在女子组中晋级成功", woman.Name);
}
}
/// <summary>
/// 失败
/// </summary>
public class Fail : Action
{
public override void GetManResult(Man man)
{
Console.WriteLine("{0}在男子组中晋级失败", man.Name);
}
public override void GetWomanResult(Woman woman)
{
Console.WriteLine("{0}在女子组中晋级失败", woman.Name);
}
}
//实现
static void Main(string[] args)
{
//3、访问者模式
Person person1 = new Man("小王");
person1.Accept(new Success());
Person person2 = new Man("小明");
person2.Accept(new Fail());
Person person3 = new Woman("小花");
person3.Accept(new Success());
Person person4 = new Woman("小美");
person4.Accept(new Fail());
Console.ReadKey();
}
3.4、迭代器模式(Iterator Pattern)
让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素
- 使用场景:需要有个方法去遍历所需内容
- 原理类图
- 项目代码
迭代器项目
1、动物类有多种存放方式:集合、List
2、同一接口实现多种存放方式的遍历输出
/// <summary>
/// 动物类
/// </summary>
public class Animal
{
private string name;
public Animal(string name)
{
this.name = name;
}
public string Name { get => name;}
}
/// <summary>
/// 迭代器接口
/// </summary>
public interface Iterator
{
/// <summary>
/// 判断是否有下一个
/// </summary>
bool HasNext();
/// <summary>
/// 下一个
/// </summary>
object Next();
/// <summary>
/// 遍历输出
/// </summary>
/// <param name="iterator"></param>
void ErgodicPrints();
}
/// <summary>
/// 动物类数组迭代器
/// </summary>
class AnimalArrayIterator : Iterator
{
private readonly Animal[] animalsArray;
private int index = 0;
public AnimalArrayIterator(Animal[] animalsArray)
{
this.animalsArray = animalsArray;
}
public bool HasNext()
{
if (index >= animalsArray.Length || animalsArray[index] == null)
{
return false;
}
return true;
}
public object Next()
{
Animal animal = animalsArray[index];
index += 1;
return animal;
}
/// <summary>
/// 遍历输出
/// </summary>
public void ErgodicPrints()
{
while (this.HasNext())
{
//输出动物类名称
Console.WriteLine(((Animal)this.Next()).Name);
}
}
}
/// <summary>
/// 动物类List迭代器
/// </summary>
class AnimalListIterator : Iterator
{
private readonly List<Animal> animalsList;
private int index = 0;
public AnimalListIterator(List<Animal> animalsList)
{
this.animalsList = animalsList;
}
public bool HasNext()
{
if(index >= animalsList.Count)
{
return false;
}
return true;
}
public object Next()
{
Animal animal = animalsList[index];
index += 1;
return animal;
}
public void ErgodicPrints()
{
while (this.HasNext())
{
//输出动物类名称
Console.WriteLine(((Animal)this.Next()).Name);
}
}
}
//实现
static void Main(string[] args)
{
//4、迭代器模式
//创建动物类数组
Animal[] animalsArray = new Animal[3] { new Animal("猫"), new Animal("狗"), new Animal("鸭子") };
//迭代器
Iterator iteratorArray = new AnimalArrayIterator(animalsArray);
iteratorArray.ErgodicPrints();
Console.WriteLine("----------------------------------------------------");
//创建动物类List
List<Animal> animalsList = new List<Animal>();
animalsList.Add(new Animal("老虎"));
animalsList.Add(new Animal("狮子"));
animalsList.Add(new Animal("豹子"));
Iterator iteratorList = new AnimalListIterator(animalsList);
iteratorList.ErgodicPrints();
Console.ReadKey();
}
3.5、观察者模式(Observer Pattern)
允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象
- 使用场景:通知和接收信息
- 原理类图
- 项目代码
订牛奶业务
1、牛奶站:实现注册、移除、通知用户还剩几瓶牛奶
2、用户:接收牛奶信息
/// <summary>
/// 发布者接口
/// </summary>
public interface ISubject {
/// <summary>
/// 注册
/// </summary>
void Register(IObserver observer);
/// <summary>
/// 移除
/// </summary>
void Remove(IObserver observer);
/// <summary>
/// 通知
/// </summary>
void Notify();
}
/// <summary>
/// 牛奶站
/// </summary>
class MilkStation : ISubject
{
//牛奶剩余数量
private int milkCount;
//观察者集合
private List<IObserver> observers = new List<IObserver>();
public int MilkCount { get => milkCount;}
/// <summary>
/// 发布最新牛奶数量
/// </summary>
/// <param name="milkCount"></param>
public void SetInfo(int milkCount)
{
this.milkCount = milkCount;
//通知所有用户
Notify();
}
public void Notify()
{
Console.WriteLine("牛奶站发出信息");
foreach (IObserver item in observers)
{
item.Update(this.milkCount);
}
}
public void Register(IObserver observer)
{
observers.Add(observer);
}
public void Remove(IObserver observer)
{
observers.Remove(observer);
}
}
/// <summary>
/// 订购者接口(观察者)
/// </summary>
public interface IObserver {
void Update(int num);
}
/// <summary>
/// 用户
/// </summary>
public class User : IObserver
{
private string name;
public User(string name)
{
this.name = name;
}
public void Update(int num)
{
Console.WriteLine("{0}收到信息:牛奶还剩{1}", name, num);
}
}
//实现
static void Main(string[] args)
{
//5、观察者模式
//牛奶站
MilkStation milkStation = new MilkStation();
//牛奶站添加用户
milkStation.Register(new Observer.User("小王"));
milkStation.Register(new Observer.User("小明"));
//发布信息
milkStation.SetInfo(3);
Console.ReadKey();
}
3.6、中介者模式(Mediator Pattern)
让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作
- 原理类图
- 项目代码
公司管理项目
1、部门:工程部、采购部、财务部
2、部门需要配合时,需要一个经理进行调配
/// <summary>
/// 中介接口
/// </summary>
public interface IMediator
{
//通知
void Notify(Department department);
}
/// <summary>
/// 经理
/// </summary>
class Manager : IMediator
{
private EngineeringDepartment engineering;
private PurchasingDepartment purchasing;
private FinanceDepartment finance;
/// <summary>
/// 将部门传入
/// </summary>
public void SetDepartment(EngineeringDepartment engineering, PurchasingDepartment purchasing, FinanceDepartment finance)
{
this.engineering = engineering;
this.purchasing = purchasing;
this.finance = finance;
}
public void Notify(Department department)
{
//收到工程部消息
if (department == engineering)
{
//同意工程部消息
department.GetMessage("同意采购一台电脑");
//把消息传达给采购部
purchasing.GetMessage("工程部需要采购一台电脑");
}
//收到采购部消息
else if (department == purchasing)
{
//同意工程部消息
purchasing.GetMessage("已告知财务部");
//把消息传达给采购部
finance.GetMessage("采购部没钱了");
}
}
}
/// <summary>
/// 部门
/// </summary>
public abstract class Department
{
protected readonly IMediator mediator;
public Department(IMediator mediator)
{
this.mediator = mediator;
}
/// <summary>
/// 向经理传达请求
/// </summary>
public abstract void Notify();
/// <summary>
/// 获取经理的信息
/// </summary>
public abstract void GetMessage(string message);
}
/// <summary>
/// 工程部
/// </summary>
public class EngineeringDepartment : Department
{
public EngineeringDepartment(IMediator mediator) : base(mediator)
{
}
public override void GetMessage(string message)
{
Console.WriteLine("工程部收到:{0}", message);
}
public override void Notify()
{
Console.WriteLine("工程部:需要采购一台电脑");
mediator.Notify(this);
}
}
/// <summary>
/// 采购部
/// </summary>
public class PurchasingDepartment : Department
{
public PurchasingDepartment(IMediator mediator) : base(mediator)
{
}
public override void GetMessage(string message)
{
Console.WriteLine("采购部收到:{0}", message);
}
public override void Notify()
{
Console.WriteLine("采购部:没钱了");
mediator.Notify(this);
}
}
/// <summary>
/// 财务部
/// </summary>
public class FinanceDepartment : Department
{
public FinanceDepartment(IMediator mediator) : base(mediator)
{
}
public override void GetMessage(string message)
{
Console.WriteLine("财务部收到:{0}", message);
}
public override void Notify()
{
}
}
//实现
static void Main(string[] args)
{
//6、中介者模式
Manager manager = new Manager();
EngineeringDepartment engineeringDepartment = new EngineeringDepartment(manager);
PurchasingDepartment purchasingDepartment = new PurchasingDepartment(manager);
FinanceDepartment financeDepartment = new FinanceDepartment(manager);
manager.SetDepartment(engineeringDepartment, purchasingDepartment, financeDepartment);
//工程部需要一台电脑,采购部去采购
engineeringDepartment.Notify();
Console.WriteLine("----------------------------------------------------");
//采购部没钱了,需要财务部给钱
purchasingDepartment.Notify();
Console.ReadKey();
}
3.7、备忘录模式(Memento Pattern)
允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态
- 使用场景:浏览器点击后退时,可返回前一个页面
- 原理类图
- 项目代码
卡牌游戏项目
1、当游戏角色攻击怪物死亡时,复活后游戏角色HP、MP恢复至打Boss前的状态
/// <summary>
/// 角色
/// </summary>
public class Role
{
private int _HP;
private int _MP;
/// <summary>
/// 赋予角色初始HP、MP
/// </summary>
public Role(int hP, int mP)
{
_HP = hP;
_MP = mP;
}
public int HP { get => _HP; set => _HP = value; }
public int MP { get => _MP; set => _MP = value; }
/// <summary>
/// 保存至备忘录
/// </summary>
public Memento SaveHPMP()
{
return new Memento(_HP, _MP);
}
/// <summary>
/// 从备忘录里获取保存的信息
/// </summary>
public void GetHPMP(Memento memento)
{
HP = memento.getHP();
MP = memento.getMP();
}
}
/// <summary>
/// 备忘录(保存角色状态)
/// </summary>
public class Memento
{
private int _HP;
private int _MP;
/// <summary>
/// 将角色HP、MP存入
/// </summary>
public Memento(int hP, int mP)
{
_HP = hP;
_MP = mP;
}
public int getHP()
{
return _HP;
}
public int getMP()
{
return _MP;
}
}
//实现
static void Main(string[] args)
{
//7、备忘录模式
//赋予角色初始100点HP和MP
Role role = new Role(100, 100);
//假定打Boos前 HP:80 MP:70
role.HP = 80;role.MP = 70;
//保存状态
Memento memento = role.SaveHPMP();
Console.WriteLine("打Boss前的状态");
Console.WriteLine("HP:{0} MP:{1}", role.HP, role.MP);
//死亡 HP:0 MP:0
Console.WriteLine("角色死了");
role.HP = 0; role.MP = 0;
Console.WriteLine("HP:{0} MP:{1}", role.HP, role.MP);
//恢复死亡之前状态
Console.WriteLine("复活为打Boos前的状态");
role.GetHPMP(memento);
Console.WriteLine("HP:{0} MP:{1}", role.HP, role.MP);
Console.ReadKey();
}
3.8、解释器模式(Interpreter Pattern)
给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。 ——《设计模式》GoF
- 原理类图
- 项目代码
实现运算
1、先输入表达式(a+b-c),表达式字母不能重复
2、分别输入a,b,c 的值
3、最后输出结果
/// <summary>
/// 表达式
/// </summary>
public abstract class Expression
{
/// <summary>
/// 例如表达式:a-b+c
/// 解释公式和数值,key就是公式参数[a,b,c],value就是具体值 例:{a=10,b=20,c=3}
/// </summary>
/// <param name="var"></param>
/// <returns></returns>
public abstract int Interpreter(Dictionary<string, int> var);
}
/// <summary>
/// 变量的解释器
/// </summary>
public class VarExpression : Expression
{
private string key;
public VarExpression(string key)
{
this.key = key;
}
/// <summary>
/// 根据key获取其对应的value
/// </summary>
public override int Interpreter(Dictionary<string, int> var)
{
return var[this.key];
}
}
/// <summary>
/// 运算符号解释器
/// </summary>
public class SymbolExpression : Expression
{
protected Expression left;
protected Expression right;
public SymbolExpression(Expression left, Expression right)
{
this.left = left;
this.right = right;
}
public override int Interpreter(Dictionary<string, int> var)
{
return 0;
}
}
/// <summary>
/// 加法解释器
/// </summary>
public class AddExpression : SymbolExpression
{
public AddExpression(Expression left, Expression right) : base(left, right)
{
}
/// <summary>
/// 处理相加
/// </summary>
public override int Interpreter(Dictionary<string, int> var)
{
return base.left.Interpreter(var) + base.right.Interpreter(var);
}
}
/// <summary>
/// 减法解释器
/// </summary>
public class SubExpression : SymbolExpression
{
public SubExpression(Expression left, Expression right) : base(left, right)
{
}
public override int Interpreter(Dictionary<string, int> var)
{
return base.left.Interpreter(var) - base.right.Interpreter(var);
}
}
/// <summary>
/// 计算
/// </summary>
public class Calculator
{
private Expression expression;
public Calculator(string expStr)
{
//栈存入表达式类型 (先入后出)
Stack<Expression> stack = new Stack<Expression>();
//将输入的表达式拆分为char数组
char[] charArray = expStr.ToCharArray();
Expression left = null;
Expression right = null;
for (int i = 0; i < charArray.Length; i++)
{
switch (charArray[i])
{
case '+':
left = stack.Pop();
right = new VarExpression(charArray[++i].ToString());
stack.Push(new AddExpression(left, right));
break;
case '-':
left = stack.Pop();
right = new VarExpression(charArray[++i].ToString());
stack.Push(new SubExpression(left, right));
break;
default: //如果不是运算符(+、-)则放入栈中
stack.Push(new VarExpression(charArray[i].ToString()));
break;
}
}
this.expression = stack.Pop();
}
/// <summary>
/// 返回运算结果
/// </summary>
public int Run(Dictionary<string,int> var)
{
return this.expression.Interpreter(var);
}
}
//实现
static void Main(string[] args)
{
//8、解释器模式
Console.WriteLine("请输入表达式:");
string expStr = Console.ReadLine();
Dictionary<string, int> var = GetValue(expStr);
Calculator calculator = new Calculator(expStr);
Console.WriteLine("运算结果:{0}={1}", expStr, calculator.Run(var));
Console.ReadKey();
}
/// <summary>
/// 将控制台输入的值写入Dictionary<string, int>键值对并返回 例:{[a:10],b:[20],c:[5]}
/// </summary>
/// <param name="expStr">表达式 例:a+b-c</param>
public static Dictionary<string, int> GetValue(string expStr)
{
Dictionary<string, int> keyValues = new Dictionary<string, int>();
foreach (char item in expStr.ToCharArray())
{
if(item != '+' && item != '-') //过滤掉加减运算符
{
if (!keyValues.ContainsKey(item.ToString())) //如果没有相同键则加入
{
Console.WriteLine("请输入{0}的值:", item.ToString());
string value = Console.ReadLine();
keyValues.Add(item.ToString(), Convert.ToInt32(value));
}
}
}
return keyValues;
}
3.9、状态模式(State Pattern)
让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样
- 原理类图
- 项目代码
文件审批发布项目
1、文件创建时为草稿状态,发布则进入审批
2、审批员审批文件草稿,通过则发表;失败则退回为草稿
3、如果管理员发现文件违规,则文件退回为草稿
/// <summary>
/// 状态类-抽象
/// </summary>
public abstract class IState
{
private string stateName = "";
/// <summary>
/// 状态名称
/// </summary>
public string StateName { get => stateName; set => stateName = value; }
/// <summary>
/// 成功
/// </summary>
public abstract void Success(Document document);
/// <summary>
/// 失败
/// </summary>
public abstract void Fail(Document document);
}
/// <summary>
/// 文件
/// </summary>
public class Document
{
private IState state;
/// <summary>
/// 文件创建时默认为草稿状态
/// </summary>
public Document()
{
state = new Draft();
}
/// <summary>
/// 更改状态
/// </summary>
/// <param name="state"></param>
public void ChangeState(IState state)
{
this.state = state;
Console.WriteLine("文件状态:" + state.StateName);
//图方便、懒得写换行
Console.WriteLine("");
}
public void Fail()
{
state.Fail(this);
}
public void Success()
{
state.Success(this);
}
}
/// <summary>
/// 草稿状态
/// </summary>
public class Draft : IState
{
public Draft()
{
base.StateName = "草稿";
}
public override void Fail(Document document)
{
//文件失败,仍为草稿状态
document.ChangeState(this);
}
public override void Success(Document document)
{
//文件成功,提交给审批
document.ChangeState(new Moderation());
}
}
/// <summary>
/// 审批状态
/// </summary>
public class Moderation : IState
{
public Moderation()
{
base.StateName = "审批";
}
public override void Fail(Document document)
{
//文件审批失败,退还为草稿
document.ChangeState(new Draft());
}
public override void Success(Document document)
{
//文件审批成功,已发表
document.ChangeState(new Published());
}
}
/// <summary>
/// 已发表状态
/// </summary>
public class Published : IState
{
public Published()
{
base.StateName = "已发表";
}
public override void Fail(Document document)
{
//发表文件违规,退还为草稿
document.ChangeState(new Draft());
}
public override void Success(Document document)
{
//文件处于已发表状态,不用执行
}
}
//实现
static void Main(string[] args)
{
//9、状态模式
//创建文档
Document document = new Document();
Console.WriteLine("1、打工仔:写文件太累了,先保存,明天再写");
document.Fail();
Console.WriteLine("2、打工仔:哦吼,终于写完文件了,提交");
document.Success();
Console.WriteLine("3、审核员:这个文件写的不错,通过了");
document.Success();
Console.WriteLine("----------------------------------------------------");
Document documentFail = new Document();
Console.WriteLine("1、打工仔:写文件太累了,先保存,明天再写");
documentFail.Fail();
Console.WriteLine("2、打工仔:哦吼,终于写完文件了,提交");
documentFail.Success();
Console.WriteLine("3、审核员:这个文件错别字太多了,退回重写");
documentFail.Fail();
Console.WriteLine("4、打工仔:文件修改完了,应该没问题了,提交");
documentFail.Success();
Console.WriteLine("5、审核员:这次文件写的不错,通过了");
documentFail.Success();
Console.WriteLine("6、管理员:这次文件违规了,退回");
documentFail.Fail();
Console.ReadKey();
}
3.10、策略模式(Stragety Pattern)
它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换
- 原理类图
- 项目代码
计算项目
1、输入两个值,分别实现加减乘除
/// <summary>
/// 算法接口
/// </summary>
public interface IStrategy
{
/// <summary>
/// 计算
/// </summary>
float Execute(int a, int b);
}
/// <summary>
/// 加法运算
/// </summary>
public class AddExecute : IStrategy
{
public float Execute(int a, int b)
{
return a + b;
}
}
/// <summary>
/// 减法运算
/// </summary>
public class SubExecute : IStrategy
{
public float Execute(int a, int b)
{
return a - b;
}
}
/// <summary>
/// 乘法运算
/// </summary>
public class MulExecute : IStrategy
{
public float Execute(int a, int b)
{
return a * b;
}
}
/// <summary>
/// 除法运算
/// </summary>
public class ExeExecute : IStrategy
{
public float Execute(int a, int b)
{
return a / b;
}
}
/// <summary>
/// 上下文
/// </summary>
public sealed class Context
{
private IStrategy strategy;
public IStrategy Strategy { get => strategy; set => strategy = value; }
public float Execute(int a, int b)
{
return Strategy.Execute(a, b);
}
}
//实现
static void Main(string[] args)
{
//10、策略模式
Context context = new Context();
//加法
context.Strategy = new AddExecute();
Console.WriteLine(context.Execute(120, 20));
//减法
context.Strategy = new SubExecute();
Console.WriteLine(context.Execute(120, 20));
//乘法
context.Strategy = new MulExecute();
Console.WriteLine(context.Execute(120, 20));
//除法
context.Strategy = new ExeExecute();
Console.WriteLine(context.Execute(120, 20));
Console.ReadKey();
}
3.11、责任链模式(Chain of Responsibility Pattern)
允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者
- 原理类图
- 项目代码
请假审批项目
1、请假两天以内(不包括两天)只用组长审批通过
2、请假两天以上(包括两天)七天以内(不包括七天)需主管审批通过
3、请假七天以上(包括七天)需经理审批通过,大于15天请假不予通过
/// <summary>
/// 请假请求
/// </summary>
public class LeaveRequest
{
/// <summary>
/// 请假人名字
/// </summary>
public string Name { get; set; }
/// <summary>
/// 请假天数
/// </summary>
public int LeaveDays { get; set; }
public LeaveRequest(string name, int leaveDays)
{
this.Name = name;
this.LeaveDays = leaveDays;
}
}
/// <summary>
/// 审批人-抽象
/// </summary>
public abstract class Approver
{
/// <summary>
/// 下一个处理者
/// </summary>
public Approver NextApprover { get; set; }
/// <summary>
/// 审批人名字
/// </summary>
public string Name { get; set; }
public Approver(string name)
{
this.Name = name;
}
public abstract void ProcessRequest(LeaveRequest leaveRequest);
}
/// <summary>
/// 组长
/// </summary>
public class GroupLeader : Approver
{
public GroupLeader(string name) : base(name)
{
}
public override void ProcessRequest(LeaveRequest leaveRequest)
{
if (leaveRequest.LeaveDays < 2)
{
Console.WriteLine("组长{0}通过了{1}请的{2}天假", base.Name, leaveRequest.Name, leaveRequest.LeaveDays);
}else
{
NextApprover.ProcessRequest(leaveRequest);
}
}
}
/// <summary>
/// 主管
/// </summary>
public class ExecutiveDirector : Approver
{
public ExecutiveDirector(string name) : base(name)
{
}
public override void ProcessRequest(LeaveRequest leaveRequest)
{
if (leaveRequest.LeaveDays >= 2 && leaveRequest.LeaveDays < 7)
{
Console.WriteLine("主管{0}通过了{1}请的{2}天假", base.Name, leaveRequest.Name, leaveRequest.LeaveDays);
}
else
{
NextApprover.ProcessRequest(leaveRequest);
}
}
}
/// <summary>
/// 经理
/// </summary>
public class Manager : Approver
{
public Manager(string name) : base(name)
{
}
public override void ProcessRequest(LeaveRequest leaveRequest)
{
if (leaveRequest.LeaveDays >= 7 && leaveRequest.LeaveDays < 15)
{
Console.WriteLine("经理{0}通过了{1}请的{2}天假", base.Name, leaveRequest.Name, leaveRequest.LeaveDays);
}
else
{
Console.WriteLine("请假天数太多不予请假");
}
}
}
//实现
static void Main(string[] args)
{
//11、责任链模式
//创建请假请求
LeaveRequest leaveRequest1 = new LeaveRequest("小王1", 1);
LeaveRequest leaveRequest2 = new LeaveRequest("小王2", 3);
LeaveRequest leaveRequest3 = new LeaveRequest("小王3", 8);
LeaveRequest leaveRequest4 = new LeaveRequest("小王4", 16);
//审批人
Approver approverG = new GroupLeader("小明");
Approver approverE = new ExecutiveDirector("小杨");
Approver approverM = new Manager("小亮");
//设置下一个处理者(链路)
approverG.NextApprover = approverE;
approverE.NextApprover = approverM;
//审批已设置成链路,必须从第一个审批人开始
approverG.ProcessRequest(leaveRequest1);
approverG.ProcessRequest(leaveRequest2);
approverG.ProcessRequest(leaveRequest3);
approverG.ProcessRequest(leaveRequest4);
Console.ReadKey();
}
总结
设计模式本质上是让项目实现高内聚低耦合,便于我们去维护项目本身(例:写一个项目没有考虑设计模式随意去写时,当需求变更,我们就需要修改原先代码,并且你修改时可能会影响原先代码中其他功能,而使用设计模式,可以让你在不修改原先代码的前提上去新增功能)