设计模式是为了让程序具有更好的
代码重用性、可读性、可拓展性、可靠性、使程序呈现高内聚,低耦合的特性。
如果软件系统过于简单,则不必要去为了OO而去OO。
1、 单一责任原则:一个类只负责一项职责
1)降低了类的复杂度,一个类只负责一项职责。
2)提高类的可读性,可维护性。
3)降低变更引起的风险。
4)通常情况下我们应该遵守单一职责原则;只有类中的方法特别少的时候,可以在方法级别保持单一职责原则。

public class RoadVehicle { public void Run(string vehicle) { Console.WriteLine(vehicle + "在公路上运行!"); } } public class RiverVehicle { public void Run(string vehicle) { Console.WriteLine(vehicle + "在河中运行!"); } } class Program { static void Main(string[] args) { RoadVehicle rv = new RoadVehicle(); rv.Run("汽车"); RiverVehicle riv = new RiverVehicle(); riv.Run("船"); Console.Read(); } }

public class Vehicle { public void RunAtRoad(string vehicle) { Console.WriteLine(vehicle + "在公路上运行!"); } public void RunInRiver(string vehicle) { Console.WriteLine(vehicle + "在河中运行!"); } } class Program { static void Main(string[] args) { Vehicle vhcl = new Vehicle(); vhcl.RunAtRoad("汽车"); vhcl.RunInRiver("船"); Console.Read(); } }
当类中的方法较少的时候,可以考虑在方法上遵守单一职责。(在方法上遵循单一,并不是一个标准的处理方式)。
使用Proxy模式,实现单一职责原则:

没有遵循单一职责原则的例子: /// <summary> /// 假定,该方法对数据库进行insert操作。 /// </summary> public void Add() { //权限判断的职责和数据库操作的职责被无礼的实现在一个类中,权限的规则变化和数据库操作的规则变化,都有可能引起DBManager修改当前代码。 if (GetPermission(id) == "CanAdd") { Console.WriteLine("管理员可以增加数据"); } } 使用代理模式对代码进行调整后,有效地实现了职责分离。 interface IDBAction { void Add(); bool Delete(); void View(); } //DBManager 只负责数据的处理。 public class DBManager : IDBAction { public void Add() { //执行数据增加 } public bool Delete() { return false; } public void View() { } } public class DBManagerProxy : IDBAction { private IDBAction dbManager; public DBManagerProxy(IDBAction dbAction) { dbManager = dbAction; } /// <summary> /// 处理权限判断的逻辑 /// </summary> /// <param name="id"></param> /// <returns></returns> public string GetPermission(string id) { //处理权限判断。 return "CanAdd"; } public void Add(string id) { if (GetPermission(id) == "CanAdd") { dbManager.Add();//调用了DBManager中的Add方法。 } } //通过代理,将数据操作和权限判断两个职责进行分离,而实际的数据操作由DBManager来执行,此时客户端的调用变的非常简单。 public bool Delete() { //部分省略.... return false; } public void View() { //部分省略.... } }
2、开闭原则
随着客户需求的变化,只是增加类,而不是修改现有的类。对拓展开放,对修改关闭。
常用的设计模式:template method,strategy。

不遵循开放封闭原则 public class BusyBankStaff { private BankProcess bankProc = new BankProcess(); public void HandleProcess(Client client) { switch (client.ClientType) { case "存款用户": bankProc.Deposit(); break; case "转账用户": bankProc.Transfer(); break; case "取款用户": bankProc.DrawMoney(); break; } } } 使用开放封闭原则,对代码进行重构 interface IBankProcess { void Process(); } class DepositProcess : IBankProcess { public void Process() { //办理存款业务。 } } class TransferProcess : IBankProcess { public void Process() { //办理转账业务。 } } class DrawMoneyProcess : IBankProcess { public void Process() { //办理转账业务。 } } class EasyBankStaff { private IBankProcess bankProc = null; public void HandleProcess(Client client) { //办理业务。 bankProc = client.CreateProcess(); bankProc.Process(); } } static void Main(string[] args) { EasyBankStaff bankStaff = new EasyBankStaff(); bankStaff.HandleProcess(new Client("转账用户")); } class Client { private string ClientType; public Client(string clientType) { ClientType = clientType; } public IBankProcess CreateProcess() { //后期可以通过依赖倒置原则,将下面的语句块给消除。 switch (ClientType) { case "存款用户": return new DepositProcess(); break; case "转账用户": return new DepositProcess(); break; case "取款用户": return new DepositProcess(); break; } return null; } }
3、依赖倒置原则
4、接口隔离原则:客户端不应该依赖它不需要的接口
5、里氏替换原则
6、迪米特法则(最少知道原则,中介者模式)
一个类对自己依赖的类知道的越少越好,对于被依赖的类来说,不管有多复杂,都尽量将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息。
一个类中,尽量不要突然出现一个局部变量(这个局部变量是另外一个类)。
只能降低类与类之间的耦合,并不能完全消除类与类之间的耦合。
7、合成复用原则
尽量使用合成/聚合的方式,而不是使用继承。
如果只是为了使用类中的方法,那么并不是一定需要去继承,可以使用组合的方式(将类的实例传进去)进行方法的调用。
创建型设计模式:
单例模式(Singleton Pattern):把对象的创建权限关闭,提供一个公开的静态方法,起到对象重用的作用。(当对象不会被频繁创建的时候,不建议使用单列,因为这样容易占内存)。
简单工厂:(不属于GOF的23种设计模式)。
工厂方法(Factory Method Pattern):每个工厂只负责一个对象的创建。
抽象工厂:每个工厂负责一个产品簇的创建。当多个对象是有机不可分的时候,可以使用抽象工厂来创建多个对象。
原型模式:把对象创建权限关闭,提供一个公开的静态方法,提供全新的对象,不走构造函数。(使用频率低)。
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。(使用频率低)。
结构型设计模式:关注类与类之间的关系。在面向对象中类与类之间进行交互,才能产生功能;纵向关系:继承/实现;横向关系:依赖、关联、组合、聚合。(关系依次变强)。
适配器模式(Adapter Pattern):在原类型不变的情况下,拓展新的接口。类适配器、对象适配器。
桥接模式(Bridge Pattern):把实现和逻辑分开,面向对象聚合复用的思想。
组合模式(Composite Pattern):不管是个体还是组件,都包含公共的操作接口,通过同样的方式来处理一个组合中的所有对象。组件的典型操作包括:增加、删除、查找、分组和获取子元素等。典型运用:树形结构的数据组织。
外观模式(Facade Pattern):将表现层和逻辑层分离,封装底层的复杂处理,为用户提供简单的接口。外观模式很多时候是一种系统架构的设计,为复杂系统的解耦,提供了最好的解决方案。
装饰模式(Decorator Pattern):为原有系统,动态的增加或删除状态和行为,在继承被装饰类的同时包含被装饰类的实例成员。.net 中的stream。
享元模式:
代理模式(Proxy Pattern):将复杂的逻辑封装起来,通过代理对象控制实际对象的创建与访问,由代理对象屏蔽原有逻辑的复杂性,同时控制其可访问性。(包一层!)
代理模式与适配器模式从代码上来看是比较接近的,代理模式是为了对原有的类进行二次封装(可以添加原本没有的功能),适配器是为了兼容。
行为型设计模式:关注行为与对象的分离
责任链模式(Chain of Responsibility Pattern):一个请求需要多个环节处理,环节还有可能拓展,变化,调整顺序等问题。
模板方法模式(Template Method Pattern):在父类中定义模板,然后由子类实现。具体的实现一般由父类定义好算法的骨架,然后将算法的某些步骤委托给子类。典型应用:asp.net 的Page类。
迭代器模式(Iterator Pattern):foreach集合。
中介者模式:
解释器模式:
命令模式(Command Pattern):将请求封装为对象,从而将命令的执行者和责任分开。通常在队列中等待命令。典型的应用:菜单系统。
观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系。当一个对象的状态发生变化的时候,所有依赖于它的对象都得到通知并被自动更新。观察者和被观察者的分开,为模块划分提供了清晰的界限。 .net中的委托和事件。
备忘录模式:
状态模式:
策略模式(Strategy Pattern):将易于变化的部分封装为接口,通常Strategy封装一些运算法则,使者能互换。
访问者模式: