设计模式共23种。主要分为三大类:创建型模式、结构型模式、行为型模式。
创建型模式:所有的模式都涉及到创建对象实例的方式。
结构型模式:如何组合类和对象以获得更大的结构。
行为型模式:通常和对象之间的通信有关。
六大设计原则:单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则、开闭原则。
创建型模式:简单工厂模式、工厂方法模式、抽象工厂模式、单件模式、生成器模式、原型模式
简单工厂模式:又叫做静态工厂方法模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
工厂方法模式:提供了一个简单的决策类,它根据提供的数据返回一个抽象基类的多个子类中的一个。
抽象工厂模式:提供了一个创建并返回一些列相关对象的接口。
单件模式:某个类只能有一个实例。它提供了一个访问该实例的全局访问点。
生成器模式:将一个复杂的构建与它的表示分开,这样就能根据程序的需要创建不同的表现形式。
原型模式:先实例化一个类,然后拷贝或克隆该类来创建新的实例,可以用公有方法进一步修改这些实例。
结构型模式:适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式
适配器模式:将一个类的接口传换成另一个类的接口。
桥接模式:可以将一个类的接口与它的实现分离,这样可以不用修改客户端代码就能改变或替换实现过程。
组合模式:是一个对象的集合,其中的任何一个对象既可以是一个组合,也可以只是一个叶子对象。
装饰模式:用一个类包装给定的类,并为它添加新的功能,将所有未改动的方法传递给下面的类。
外观模式:将一系列复杂的对象放在一起,并提供一个新的、更简单的访问这些数据的接口。
享元模式:把一部分的类数据移到类外部,在执行方法时将数据传递进来,通过这种方式限制那些又小又相似的实例的增加数量。
代理模式:为一个比较复杂的对象提供一个简单的占位对象,实例化该复杂对象,在某种程度上比较浪费时间或代价较高。
行为型模式:职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式
职责链模式:把请求从链中的一个对象传递到下一个对象,直到请求被响应为止。通过这种方式在对象之间去除耦合。
命令模式:用简单的对象表示软件命令的执行,支持登陆和取消操作。
解释器模式:提供一个如何把语言元素包含在程序中的定义。
迭代器模式:提供了一种顺序访问一个类中的一系列数据的方式。
中介者模式:定义了如何用一个对象简化对象之间的通信,是对象之间不必相互了解。
备忘录模式:定义了如何保存一个类实例的内容以便以后能恢复它。
观察者模式:定义了一种把改动通知给多个对象的方式。
状态模式:允许一个对象在其内部状态改变时修改它的行为。
策略模式:将算法封装到类里。
模板方法模式:提供了算法的抽象定义。
访问者模式:在不改变类的前提下,为一个类添加多种操作。
设计模式六大原则(1):单一职责原则
定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。解决方案:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职
设计模式六大原则(2):里氏替换原则
定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
定义2:所有引用基类的地方必须能透明地使用其子类的对象。
问题由来:有一功能P1,由类A完成。现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。新功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障。
解决方案:当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。
继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。
责P1发生故障风险。
设计模式六大原则(3):依赖倒置原则
定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。依赖倒置原则的核心思想是面向接口编程。
设计模式六大原则(4):接口隔离原则
定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。
采用接口隔离原则对接口进行约束时,要注意以下几点:
• 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
• 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
• 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。运用接口隔离原则,一定要适度,接口设计的过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。
设计模式六大原则(5):迪米特法则
定义:一个对象应该对其他对象保持最少的了解。问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
解决方案:尽量降低类与类之间的耦合。
设计模式六大原则(6):开闭原则
定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。
解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
系列导航:
C#设计模式(1)——单例模式
C#设计模式(2)——简单工厂模式
C#设计模式(3)——工厂方法模式
C#设计模式(4)——抽象工厂模式
C#设计模式(5)——建造者模式(Builder Pattern)
C#设计模式(6)——原型模式(Prototype Pattern)
C#设计模式(7)——适配器模式(Adapter Pattern)
C#设计模式(8)——桥接模式(Bridge Pattern)
C#设计模式(9)——装饰者模式(Decorator Pattern)
C#设计模式(10)——组合模式(Composite Pattern)
C#设计模式(11)——外观模式(Facade Pattern)
C#设计模式(12)——享元模式(Flyweight Pattern)
C#设计模式(13)——代理模式(Proxy Pattern)
C#设计模式(14)——模板方法模式(Template Method)
C#设计模式(15)——命令模式(Command Pattern)
C#设计模式(16)——迭代器模式(Iterator Pattern)
C#设计模式(17)——观察者模式(Observer Pattern)
C#设计模式(18)——中介者模式(Mediator Pattern)
C#设计模式(19)——状态者模式(State Pattern)
C#设计模式(20)——策略者模式(Stragety Pattern)
C#设计模式(21)——责任链模式
C#设计模式(22)——访问者模式(Vistor Pattern)
C#设计模式(23)——备忘录模式(Memento Pattern)
参考文章:C#设计模式总结 - 凡的世界 - 博客园