声明:部分内容属于摘录,其余多是个人总结,仅供学习参考。
设计模式主要分三个类型:创建型、结构型和行为型。
创建型:
1、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点
2、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。
3、Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。
4、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。
5、Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。
行为型:
6、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。
7、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。
8、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。
9、Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。
10、State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。
11、Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。
12、China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
13、Mediator,中介者模式:用一个中介对象封装一系列的对象交互,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。
14、Visitor,访问者模式:封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。
15、Interpreter,解释器模式:给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
16、Memento,备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。
结构型:
17、Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。
18、Facade,外观模式:为子系统中的一组接口提供一致的界面,Facade模式提供了一高层接口,这个接口使得子系统更容易使用。
19、Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问。
20、Adapter,适配器模式:将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。
21、Decrator,装饰模式:动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活,是除类继承外另一种扩展功能的方法。
22、Bridge,桥接模式:将抽象部分与它的实现部分相分离,使他们可以独立的变化。
23、Flyweight,享元模式:通过共享以便有效的支持大量小颗粒对象。
定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。
解决方案:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。
肯定有不少人跟我刚看到这项原则的时候一样,对这个原则的名字充满疑惑。其实原因就是这项原则最早是在1988年,由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。
定义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的方法。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。
定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
传递依赖关系有三种方式,以上的例子中使用的方法是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递,相信用过Spring框架的,对依赖的传递方式一定不会陌生。
定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。
解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。
定义:一个对象应该对其他对象保持最少的了解。
问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
解决方案:尽量降低类与类之间的耦合。
只与直接的朋友通信。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。
定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。
解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
用抽象构建框架,用实现扩展细节。
对这六个原则的遵守并不是是和否的问题,而是多和少的问题,也就是说,我们一般不会说有没有遵守,而是说遵守程度的多少。任何事都是过犹不及,设计模式的六个设计原则也是一样,制定这六个原则的目的并不是要我们刻板的遵守他们,而需要根据实际情况灵活运用。对他们的遵守程度只要在一个合理的范围内,就算是良好的设计。我们用一幅图来说明一下。
图中的每一条维度各代表一项原则,我们依据对这项原则的遵守程度在维度上画一个点,则如果对这项原则遵守的合理的话,这个点应该落在红色的同心圆内部;如果遵守的差,点将会在小圆内部;如果过度遵守,点将会落在大圆外部。一个良好的设计体现在图中,应该是六个顶点都在同心圆中的六边形。
一般来说,常用的设计模式有以下八种:单例、工厂、观察者、代理、命令、适配器、合成、访问者
(类)目的是为了让系统中只有一个调用对象,缺点是单例使其他程序过分依赖它,而且不同单例运行在不同进程中,使得维护困难;
1.构造函数私有化
2.定义一个私有的静态的该类的实例
3.定义一个公共的返回该类实例的方法
和其抽象方法,抽象多(接口-实现类-工厂类)生产固定的一些东西,如抽象类,缺点是产品修改麻烦;如喜欢动作片和爱情片的人分别向服务器发出同一个请求,就可以得到他们想看的影片集,相当于不同对象进行同一请求,需求均得到满足。分三种:
步骤:
a.普通工厂模式
1.定义一个接口和其抽象方法,抽象多个类的共同职责(比如发送邮件和发送短信都有发送动作 I:Sender->send())
2.定义不同的(抽象)类来实现这个接口(发送邮件的MailSender和发送短信的SmsSender)
3.创建工厂类(只包含一个方法),根据不同条件(传入参数不同)返回不同的类的实例
b.多个工厂方法模式
上述步骤3中创建工厂类时创建多个方法,返回不同实例
c.静态工厂方法模式
上述步骤3中创建工厂类时可将创建的方法设置为静态的,此时不需要实例化工厂类,较常用,对应的方法为静态工厂方法
实例:Android中Connection类既充当抽象产品类,也充当具体工厂类,其中getConnection方法就是静态工厂方法。
就是多个对象对一个对象进行监控,如缓存
自己的事交给别人去做,分别返回结果即可,如异步线程
1.定义一个接口和抽象方法
2.定义原始类和代理类实现接口,代理类中持有对原始类的实例引用,在复写的方法中操作需求
3.定义原始类的引用纸箱代理实例,执行原始类方法,实际执行的是代理类的方法
调用对象与作用对象之间分离(解耦),由中间件来协调两者之间的工作,如控制器
1.定义命令接口(或抽象类)和要执行的抽象方法。(I:Command->exe())
2.定义命令的接受类和处理命令的方法。(C:Receiver->action())
3.实现命令接口,持有接收对象,在实现的抽象方法中执行接收对象的处理命令的方法。
4.定义命令发送类,持有命令对象和发命令的方法,方法中执行命令。(C:Invoker->action())
5.新建命令,传入命令的接收者,将该命令传入命令发送类的实例,执行实例的发命令动作。(new Invoker(new MyCommand(new Receiver()))).action();
将一个接口变成用户所需要的接口,如baseadapter可以适配listview和spinner,因为它们有相同的接口。分三种:
a.类适配器
1.定义待适配的类和方法。
2.定义目标接口,与带适配的类中方法相同,加上新类(适配器)的方法。
3.定义adapter适配类继承带适配类并实现目标接口,实现新类的方法。
4.定义目标接口的引用指向适配类,分别执行其新旧方法,可使目标接口的实现类具有带适配类的功能。
b.对象适配器(与类适配的区别在于定义适配类时传入待适配实例)
1.2.同上
3.在定义适配类时传入待适配类的实例,旧方法中执行待适配实例的方法
4.定义目标接口的引用指向适配类,适配类中传入待适配类实例,执行目标接口实例的方法即可。
c.接口适配器
1.定义接口和对应抽象方法
2.定义抽象类实现接口
3.定义若干具体类继承抽象类,分别复写不同方法
4.定义接口的引用指向具体类,根据需求执行其不同方法
将一对多的关系转成一对整体的关系,如listview与适配器
对不同的对象采取不同的处理,如instanceof。
1.定义访问接口,抽象方法中传入要访问的对象
2.实现访问接口
3.定义目标接口,一个抽象方法接受要访问它的对象,另一个获取将要被访问的属性
4.实现目标接口
5.将实现访问接口的实例传入实现目标接口的实例的接收方法。