23种设计模式【C#代码举例】(上):https://developer.aliyun.com/article/1556288
第十五章 抽象工厂模式 167
提供一个创建一系列相关或者额相互依赖的对象的接口,而无需指定它们的具体的类;
//数据实体 public class DataUser { public DataUser(string name,string id) { Name = name;Id = id; } public string Name { get; set; } public string Id { get; set; } } public class DataDepartment { public DataDepartment(string deptname, string id) { Deptname = deptname; Id = id; } public string Deptname { get; set; } public string Id { get; set; } } //User操作接口 public interface IUser { public void Insert(DataUser u); public DataUser Get(); } //User操作具体类 public class SqlserverUser : IUser { public DataUser Get() { Console.WriteLine("Sqlserver获取用户"); return null; } public void Insert(DataUser u) { Console.WriteLine("Sqlserver添加用户"); } } public class AccessUser : IUser { public DataUser Get() { Console.WriteLine("Access获取用户"); return null; } public void Insert(DataUser u) { Console.WriteLine("Access添加用户"); } } //Department操作接口 public interface IDepartment { public void Insert(DataDepartment d); public DataDepartment Get(); } //Department操作具体类 public class SqlserverDepartment : IDepartment { public DataDepartment Get() { Console.WriteLine("Sqlserver获取部门"); return null; } public void Insert(DataDepartment d) { Console.WriteLine("Sqlserver添加部门"); } } public class AccessDepartment : IDepartment { public DataDepartment Get() { Console.WriteLine("Access获取部门"); return null; } public void Insert(DataDepartment d) { Console.WriteLine("Access添加部门"); } } //操作类工厂接口 public interface IFactory { public IUser CreateUser(); public IDepartment CreateDepartment(); } //操作类工厂的具体实现类 class SqlserverFactory : IFactory { public IDepartment CreateDepartment() { return new SqlserverDepartment(); } public IUser CreateUser() { return new SqlserverUser(); ; } } class AccessFactory : IFactory { public IDepartment CreateDepartment() { return new AccessDepartment(); } public IUser CreateUser() { return new AccessUser(); ; } } --测试:换了工厂类factory,数据库访问则被更换; DataUser user=new DataUser("张三","U01"); DataDepartment dept = new DataDepartment("财务部","D001"); //IFactory factory = new AccessFactory(); IFactory factory = new SqlserverFactory(); IUser iu= factory.CreateUser(); IDepartment idept= factory.CreateDepartment(); iu.Insert(user); iu.Get(); idept.Insert(dept); idept.Get();
缺点:增加一个表project;需要增加DataProject数据类。还需要增加三个操作类IProject,SQLserverProject,AccessProject,修改三个类,IFactory,SQLserverFactory,AccessFactory。
更换数据库是方便,但是实现过程,每增加一个表,要增加或更改的地方太多了。
关于抽象工厂的优化:用简单工厂完成factory的部分;一个DataAccess工具类足矣(不同数据库的相应表的操作类实例化);略;
对抽象工厂优秀的优化方案:反射+抽象工厂
Assembly.Load(“程序集名称”).CreateInstance(命名空间.类名称);
常规活的实例的方法
IUser iu=new SqlserverUser();
反射获取实例方法
IUser iu=(IUser)Assembly.Load(“AbsFactory”).CreateInstance(“AbsFactory.Sqlserver”);
实现后的DataAccess如下;
class DataAccess { private static readonly string AssemblyName = "AbsFactory"; private static readonly string db = "sqlserver"; public static IUser CreateUser() { string classname = AssemblyName + "." + db + "User"; return (IUser)Assembly.Load(AssemblyName).CreateInstance(classname); } public static IDepartment CreateDepartment() { string classname = AssemblyName + "." + db + "Department"; return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(classname); } }
如果增加了一个表Project。则DataAccess增加一个CreateProject方法;增加三个Project相关类;
更优化的方法:
将数据库字符串放在配置文件中。这样改变数据库,只需要改变配置文件,而不需要重新编译程序;这样会少了一些关于数据库选择Switch语句;
第十六章 状态模式
当一个对象状态改变时,允许改变起行为,这个对象看起来像是改变了其类;
优点:将于特定状态相关的行为局部化,并且将不同状态的行为分割开来;
使用时机:一个对象的行为取决于他的状态,并且它必须在运行时时刻根据状态改变行为,此时可以考虑使用状态模式。
每个状态对应一个状态类,改变状态就是改变了状态类。
public class Work { public double Hour { get; set; } public bool Finish { get; set; } public State State { get; set; } public Work() { State=new ForenoonState(); } public void SetState(State s) { State = s; } public void WriteProgram() { State.WriteProgram(this); } } //抽象状态类 public abstract class State { public abstract void WriteProgram(Work w); } //具体状态:上午 public class ForenoonState : State { public override void WriteProgram(Work w) { if (w.Hour < 12) { Console.WriteLine("当前时间:{0}点,上午工作,精神百倍。",w.Hour); } else { w.SetState(new NoonState()); w.WriteProgram(); } } } //具体状态:中午 public class NoonState : State { public override void WriteProgram(Work w) { if (w.Hour >=12&&w.Hour<=13) { Console.WriteLine("当前时间:{0}点,中午工作,精神不太好。", w.Hour); } else { w.SetState(new AfternoonState()); w.WriteProgram(); } } } //具体状态:下午 public class AfternoonState : State { public override void WriteProgram(Work w) { if (w.Hour > 13) { Console.WriteLine("当前时间:{0}点,上午工作,精神还可以。", w.Hour); } else { w.SetState(new ForenoonState()); w.WriteProgram(); } } } --代码测试 //状态模式 Work w = new Work(); w.Hour = 9; w.WriteProgram(); w.Hour = 10; w.WriteProgram(); w.Hour = 11; w.WriteProgram(); w.Hour = 12; w.WriteProgram(); w.Hour = 13; w.WriteProgram(); w.Hour = 14; w.WriteProgram(); w.Hour = 15; w.WriteProgram(); w.Hour = 16; w.WriteProgram();
第十七章 适配器模式 197
将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。
适配器分类:
类适配器:通过多重继承对一个接口与另一个接口进行匹配。很多语言不支持多重继承。
对象适配器:主要的适配器类别。
使用时机:两个类所做事情相同或类似,单具有的接口不同;而双方都不易修改;
//目标,客户需求接口 public class Target { public virtual void Request() { Console.WriteLine("普通请求!"); } } //需要适配的类 class Adaptee { public virtual void SpecificRequest() { Console.WriteLine("特殊请求!"); } } //适配器,通过内部包装一个需要适配的类,把源接口转换成目标接口 class Adapter :Target { private Adaptee adaptee = new Adaptee(); public override void Request() { adaptee.SpecificRequest(); } } //测试代码 Target target = new Adapter(); target.Request();
第十八章 备忘录模式 206
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以讲该对象恢复到原先保存的状态。
我首先想到的就是单机游戏的存档。
发起人:创建备忘录memento;
备忘录memento:存储对象状态;
管理者:保存备忘录;
场合:功能复杂,需要维护或记录属性历史的类,或者需要保存属性只是众多属性中一部分。可以更具备忘录保存的信息还原到前一状态。
//发起人 public class Originator { public string State { get; set; } public Memento CreateMemento() { return new Memento(State); } public void SetMemento(Memento memento) { State = memento.State; } public void Show() { Console.WriteLine("State={0}",State); } } //备忘录 public class Memento { public String State { get; set; } public Memento(string state) { State = state; } } //管理者 public class Caretaker { public Memento memento { get; set; } } //测试代码 Originator o = new Originator(); o.State = "On"; o.Show(); Caretaker caretaker = new Caretaker(); caretaker.memento = o.CreateMemento(); o.State = "Off"; o.Show(); o.SetMemento(caretaker.memento); o.Show();
第十九章 组合模式 215
将对象组合成树形结构以表示部分和整体的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性;
使用的时机:需求是提现部分与整体的层次结构,并忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时,考虑使用组合模式;
abstract class Componet { protected Componet(string name) { Name = name; } public abstract string Name { get; set; } public abstract void Add(Componet c); public abstract void Remove(Componet c); public abstract void Display(int depth); } class Leaf : Componet { public Leaf(string name):base(name) { } public override string Name { get; set; } public override void Add(Componet c) { Console.WriteLine("Can't add to a leaf"); } public override void Display(int depth) { Console.WriteLine(new String('-',depth)+Name); } public override void Remove(Componet c) { Console.WriteLine("Can't remove from a leaf"); } } class Composite : Componet { public List<Componet> children { get; set; }= new List<Componet>(); public Composite(string name) : base(name) { } public override string Name { get; set; } public override void Add(Componet c) { children.Add(c); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + Name); foreach(var c in children) { c.Display(depth + 2); } } public override void Remove(Componet c) { children.Remove(c); } } //测试代码 Composite root = new Composite("root"); root.Add(new Leaf("Leaf A")); root.Add(new Leaf("Leaf B")); Composite comp = new Composite("composite X"); comp.Add(new Leaf("Leaf XA")); comp.Add(new Leaf("Leaf XB")); root.Add(comp); Composite comp1 = new Composite("composite XY"); comp1.Add(new Leaf("Leaf XYA")); comp1.Add(new Leaf("Leaf XYB")); root.Add(comp1); root.Display(0);
第二十章 迭代模式
提供一种方法,顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
//迭代器抽象类 abstract class Iterator { public abstract object First(); public abstract object Next(); public abstract bool IsDone(); public abstract object CurrentItem(); } //聚集抽象类 abstract class Aggregate { public abstract Iterator CreaeteIterator(); } //具体迭代类,继承抽象迭代器 class ConcreteIterator : Iterator { private ConcreteAggregate aggregate; private int current=0; public ConcreteIterator(ConcreteAggregate aggregate) { this.aggregate = aggregate; } public override object CurrentItem() { return aggregate[current]; } public override object First() { return aggregate[0]; } public override bool IsDone() { return current>=aggregate.Count; } public override object Next() { object ret = null; current ++; if (current < aggregate.Count) { ret= aggregate[current]; } return ret; } } //具体聚集类,继承Aggieregate class ConcreteAggregate : Aggregate { private IList<Object> items = new List<Object>(); public int Count { get { return items.Count; } } public Object this[int index] { get { return items[index]; } set { items.Insert(index, value); } } public override Iterator CreaeteIterator() { throw new NotImplementedException(); } } //代码测试 ConcreteAggregate a = new ConcreteAggregate(); a[0] = "大鸟0"; a[1] = "大鸟1"; a[2] = "大鸟2"; a[3] = "大鸟3"; a[4] = "大鸟4"; Iterator i = new ConcreteIterator(a); object item = i.First(); while (!i.IsDone()) { Console.WriteLine("买票:{0}",i.CurrentItem()); i.Next(); }
现在泛滥的for应用,使得迭代模式在很多集合中已经实现。所以自定义的迭代模式极少。甚至有人呼吁取消迭代模式;
第二十一章 单例模式 236
保证一个类只有一个实例,并提供一个访问它的全局访问点。
//多线程时的单例 public class Singleton { private static Singleton? instance; private readonly static object syncRoot=new object(); private Singleton() { } public static Singleton GetInstance() { //双重锁,去掉外层if也可以,就变成了单层锁 if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
静态初始化
//静态初始化,要点就是sealed(阻止派生)和readonly(一次创建) public sealed class Singleton { private static readonly Singleton instance = new Singleton(); private Singleton() { } public static Singleton GetInstance() { return instance; } }
第二十二章 桥接模式 247
桥接模式:将抽象部分与它的实现部分分离,使他们都可以独立变化;
//手机软件,抽象类 public abstract class HandsetSoft { public abstract void Run(); } //手机软件,具体类 public class HandsetGame : HandsetSoft { public override void Run() { Console.WriteLine("运行手机游戏"); } } public class HandsetAddressList : HandsetSoft { public override void Run() { Console.WriteLine("运行手机通讯录"); } } //手机品牌抽象类 abstract class HandsetBrand { public HandsetSoft soft { get; set; } public abstract void Run(); } //具体的手机品牌M,N class HandSetBrandM : HandsetBrand { public override void Run() { soft.Run(); } } class HandSetBrandN : HandsetBrand { public override void Run() { soft.Run(); } }
测试代码
HandsetBrand ab = new HandSetBrandN(); ab.soft = new HandsetGame(); ab.Run(); ab.soft= new HandsetAddressList(); ab.Run(); ab = new HandSetBrandM(); ab.soft = new HandsetGame(); ab.Run(); ab.soft = new HandsetAddressList(); ab.Run();
如果新增了Mp3,则只需要新增一个类
public class HandsetMp3 : HandsetSoft { public override void Run() { Console.WriteLine("运行手机Mp3"); } }
第二十三章 命令模式 261
将一个请求封装为一个对象,从而使你可用不同的请求对客户参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
//接受者:烤串的人; class Receiver { public void Action() { Console.WriteLine("执行请求"); } } //抽象命令 abstract class Command { public Receiver receiver { get; set; } public Command(Receiver receiver) { this.receiver = receiver; } abstract public void Execute(); } //具体命令 class ConcreteCommand : Command { public ConcreteCommand(Receiver receiver) : base(receiver) { } public override void Execute() { receiver.Action(); } } //要求该命令执行这个请求 :服务员 class Invoker { public Command command { get; set; } public void ExecuteCommand() { command.Execute(); } }
执行代码 客户
Receiver r = new Receiver(); Command c = new ConcreteCommand(r); Invoker i = new Invoker(); i.command=c; i.ExecuteCommand();
整个过程就是:客户喊了个服务员,制定了一个命令。服务员带着命令,让执行者执行命令;
第二十四章 责任链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的偶合。将这个对象连成一个链,并沿着这条链传递改请求,直到有一个对象处理它 。
//申请 class Request { public string requestType { get; set; } public string requestContent { get; set; } public int requestNumber { get; set; } public Request(string requestType, string requestContent, int requestNumber) { this.requestType = requestType; this.requestContent = requestContent; this.requestNumber = requestNumber; } } //管理者 abstract class Manager { public string Name { get; set; } //上级 public Manager superior { get; set; } protected Manager(string name) { Name = name; } protected Manager(Manager superior) { this.superior = superior; } abstract public void RequestApplications(Request request); } //经理 class CommonManager : Manager { public CommonManager(string name) : base(name) { } public override void RequestApplications(Request request) { if (request.requestType == "请假" && request.requestNumber <= 2) { Console.WriteLine( "{0}:{1}{2}天被批准!",Name,request.requestContent,request.requestNumber); } else { if (superior != null) { superior.RequestApplications(request); } } } } //总监 class MajorManager : Manager { public MajorManager(string name) : base(name) { } public override void RequestApplications(Request request) { if (request.requestType == "请假" && request.requestNumber <= 5) { Console.WriteLine("{0}:{1}{2}天被批准!", Name, request.requestContent, request.requestNumber); } else { if (superior != null) { superior.RequestApplications(request); } } } } //总经理 class BossManager : Manager { public BossManager(string name) : base(name) { } public override void RequestApplications(Request request) { if (request.requestType == "请假") { Console.WriteLine("{0}:{1}{2}天被批准或者拒绝!", Name, request.requestContent, request.requestNumber); } else if (request.requestType == "加薪") { Console.WriteLine("{0}:{1}数量{2}被批准或者拒绝!", Name, request.requestContent, request.requestNumber); } } } //测试代码 CommonManager jinli = new CommonManager("锦鲤经理"); MajorManager major = new MajorManager("卡卡总监"); BossManager boss = new BossManager("博士老总"); jinli.superior = major; major.superior = boss; Request request = new Request("请假","小菜请假",3); jinli.RequestApplications(request);
上面的管理者只列出了上级;
关于请求的发起来源及提交下级的情况应该怎么记录,做出思考;发起来源可以放在请求里;提交来源可以放在请求里,流程经手人都可以放在请求里按顺序存放。
第二十五章 中介者模式
中介者,也叫调停者。
中介者模式:用一个中介对象封装一些列的对象交互。中介者使各对象不要显式地相互作用,从而使其耦合松散,而且可以独立改变他们之间的交互。
//抽象中介者:联合国机构 abstract class UnitedNations { //声明 public abstract void Declare(string message,Country colleague); } //具体的中介 安理会 class UnitedNationsSecurityCouncil : UnitedNations { public USA c1; public Iraq c2; public override void Declare(string message, Country colleague) { if (colleague == c1) { c2.GetMessage(message); } else if(colleague == c2) { c1.GetMessage(message); } } } //需要被中介的抽象类:国家 abstract class Country { public UnitedNations mediator { get; } protected Country(UnitedNations mediator) { this.mediator = mediator; } } //具体的国家类 class USA : Country { public USA(UnitedNations mediator) : base(mediator) { } public void Declare(string message) { mediator.Declare(message, this); } public void GetMessage(string message) { Console.WriteLine("USA获得消息:"+message); } } class Iraq : Country { public Iraq(UnitedNations mediator) : base(mediator) { } public void Declare(string message) { mediator.Declare(message, this); } public void GetMessage(string message) { Console.WriteLine("伊拉克获得消息:" + message); } } //测试代码 UnitedNationsSecurityCouncil uni = new UnitedNationsSecurityCouncil(); USA usa = new USA(uni); Iraq iraq = new Iraq(uni); uni.c1=usa; uni.c2=iraq; usa.Declare("美国声明:我要打你了"); iraq.Declare("伊拉克声明:你可以试试");
最简单的就是1对1的中介模式;也可以是1对多模式;多对多模式我暂时没想出来;但是只要制定了规则,多对多按规则交互也是可以的。就是按规则在中间类内部进行了信息的交流。
第二十六章 享元模式
享元模式:运用共享技术有效支持大量细粒度的对象。
//用户 public class User { public string Name { get; set; } public User(string name) { Name = name; } } //抽象网站 abstract class WebSite { public abstract void Use(User user); } //实际网站 class ConcreteWebSite : WebSite { public string Name { get; set; } public ConcreteWebSite(string name) { Name = name; } public override void Use(User user) { Console.WriteLine("网站分类:{0} ;用户:{1}",Name ,user.Name); } } //网站工厂 class WebSiteFactory { public Hashtable flyweights = new Hashtable(); //获得网站分类 public WebSite GetWebSiteCategory(string key) { if (!flyweights.ContainsKey(key)) { flyweights.Add(key, new ConcreteWebSite(key)); } return (WebSite)flyweights[key]; } //获取网站个数 public int GetWebSiteCount() { return flyweights.Count; } } //测试代码 WebSiteFactory factory = new WebSiteFactory(); WebSite w1= factory.GetWebSiteCategory("展品展示"); w1.Use(new User("小菜2")); WebSite w2 = factory.GetWebSiteCategory("展品展示"); w1.Use(new User("小菜1")); WebSite w3 = factory.GetWebSiteCategory("展品展示"); w1.Use(new User("小菜3")); WebSite w4 = factory.GetWebSiteCategory("博客"); w1.Use(new User("小菜4")); WebSite w5 = factory.GetWebSiteCategory("博客"); w1.Use(new User("小菜5")); WebSite w6 = factory.GetWebSiteCategory("博客"); w1.Use(new User("小菜2")); Console.WriteLine("网站分类总数:{0}",factory.GetWebSiteCount());
分类不同才是真的不同。账号不同就是根据账号区分一下数据。
第二十七章 解释器模式
解释器模式:给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
时机:一种特定类型的问题发生频率足够高,那么可能就值得将该问题各个实例表述为一个简单语言中的句子。这样就可以构成一个解释器,该解释器通过解释这些句子来解决该问题。
举例:正则表达式;
class Context { public Context(string input) { Input = input; } public string Input { get; set; } public string Output { get; set; } } //抽象表达式 abstract class AbstractExpression { //解释器 public abstract void Interpret(Context context); //执行:如有必要,可以有多个执行; public abstract void Excute(string key, string value); } //A解释器 class AExpression : AbstractExpression { public override void Excute(string key, string value) { if (key == "A") { Console.WriteLine("A终端解释器:{0}-{1}", key, value); } } public override void Interpret(Context context) { { Dictionary<string, string> dict = new Dictionary<string, string>(); for (int i = 0; i < context.Input.Length / 2; i++) { string key = context.Input.Substring(2 * i, 1); string value = context.Input.Substring(2 * i + 1, 1); Excute(key, value); } } } } //B解释器 class BExpression : AbstractExpression { public override void Excute(string key, string value) { if (key == "B") { Console.WriteLine("A终端解释器:{0}-{1}", key, value); } } public override void Interpret(Context context) { { Dictionary<string, string> dict = new Dictionary<string, string>(); for (int i = 0; i < context.Input.Length / 2; i++) { string key = context.Input.Substring(2 * i, 1); string value = context.Input.Substring(2 * i + 1, 1); Excute(key, value); } } } } //执行代码 Context context = new Context("A0B2C3A4B5A6B8B9A0AaBb"); AbstractExpression expression=new BExpression(); expression.Interpret(context); Console.ReadLine();
解释器,文法规则的设计很重要。
第二十八章 访问者模式
表示一个作用于某对象结构中的各元素操作。他使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
//抽象被访问者 public abstract class Person { public abstract void Accept(Action visitor); } public class Man : Person { public override void Accept(Action visitor) { visitor.VisitMan(this); } } public class WoMan : Person { public override void Accept(Action visitor) { visitor.VisitWoMan(this); } } //抽象提问 public abstract class Action { public abstract void VisitMan(Man man); public abstract void VisitWoMan(WoMan woman); } //成功 class Success : Action { public override void VisitMan(Man man) { Console.WriteLine("{0}{1}时,背后多半有一个伟大的女人!",man.GetType().Name,this.GetType().Name); } public override void VisitWoMan(WoMan woman) { Console.WriteLine("{0}{1}时,背后多半有一个失败的男人!", woman.GetType().Name, this.GetType().Name); } } //结婚 class Merry : Action { public override void VisitMan(Man man) { Console.WriteLine("{0}{1}时,【有妻徒刑】开始执行!", man.GetType().Name, this.GetType().Name); } public override void VisitWoMan(WoMan woman) { Console.WriteLine("{0}{1}时,【爱情保险】开始生效!", woman.GetType().Name, this.GetType().Name); } } //测试代码 List<Console23Style.HK.Visitor.Person> ps = new List<Console23Style.HK.Visitor.Person>(); ps.Add(new Man()); ps.Add(new WoMan()); Success success = new Success(); Merry merry = new Merry(); foreach (Console23Style.HK.Visitor.Person p in ps) { p.Accept(success); p.Accept(merry); }
多一个话题,既需要多一个action的子类;对Person和其子类没有影响;