策略模式
定义
定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使算法的客户。
变化分离原则:
找出应用中可能变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
比如此时的飞和叫就是变化的行为,我们将他们从duck类中抽取出来,建立一组新的类代表每个行为。
模式应用
在此模式中,将变化的行为抽离,设置两个额外的接口,这个额外的接口有自己的实现类,在定义Duck类(抽象类)的时候,要定义两个接口的变量,然后具体子类实现的时候,再调用fly方法的时候,就用该变量来调用。
设计原则
面向接口编程,而不是面对实现编程。
这句话的意思是说变量的声明类型或者方法的返回值类型是是个超类型,而不是某个具体的子类。超类型的各个方法的具体实现不是在超类型中,而是在各个子类中。
好处:这是一种松耦合的思想,我们在维护的时候随时将声明的变量替换为所需要的类型,具有很高的可维护性和扩展性。
例如 动物的叫行为:
针对实现编程就是: void hearquack(new cow());
Void hearquack(new chicken());
Void hearquack(new bird());
即申明无数个方法,针对每一个具体的类进行编程
针对接口编程就是:
Void hearquack( new animal());
调用时采用heardquack(new cow())或者其他。
只声明一个方法带有超类的参数。
设计原则
多用组合,少用继承。
指的是鸭子的行为对象不是继承而来的,而是和适当的行为对象组合而来的。
适配器模式
模式定义
将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的接口可以合作无间。
模式应用
在此模式中,定义抽象的适配器类,这个类继承狼和羊的接口,并且实现他们两个的方法,实现捉羊方法的时候,实际上是调用了逃跑方法,相同在实现逃跑方法的时候,实际上是调用了捉羊方法。
设计原则
使用对象组合,以修改的接口包装被适配者。
装饰者模式
设计原则
- 对修改关闭,对扩展开放。
- 多用组合,少用继承。
利用继承设计子类的行为,是在编译时静态决定的,而且所有子类会继承到相同的行为,利用组合的话,就可以在运行时动态的进行扩展。
模式说明
在不改变原类对象和使用继承的基础上,动态的扩展一个对象的功能。创建装饰者类,就是用装饰来包裹真实的对象。
模型实现
定义一个共同的基类,即饮料类,调料类和饮品类都继承这个类,调料类也是一个抽象的类,调料继承这个抽象的类,在调料类中有一个饮料类的对象,用层层的调料包裹这个饮料,就可以达到运行时动态扩展对象行为的功能。
观察者模式
模式定义
在对象之间定义了一对多的模式,当一个对象的改变状态,那么依赖他的对象都会收到通知,并且自动更新。
模式应用
实现两个接口,分别为主题接口和观察者接口,用子类实现两个接口,在主题接口的实现类中构造了一个观察者列表,分别设置有通知,删除,获取信息等方法,当获取了新的消息需要通知观察者时,就遍历列表,调用观察者的更新信息方法。(推)
观察者模式中有推和拉两种方式,在推模式中,不管观察者是否需要,都会将信息传递给观察者,这是update函数的参数实际上是一段信息,与拉模式不同,拉模式可以自主选择自己需要的信息,在update函数中传递的则是一个subject的对象,由观察者自主选取所需要的信息。
设计原则
为交互对象之间的松耦合设计而努力
之所以说是松耦合的原因:
关于观察者的一切,主题并不关心,主题并不知道观察者的具体类是谁,做了什么,只知道观察者实现了观察者接口。
在任何时候,我们都可以增加或者删除观察者,因为主题依赖的仅仅是一个观察者列表,改变主题或者观察中的一方,并不会影响另一方,因为两者之间是松耦合的,我们可以自由的改变他们。
它将对象之间的相互依赖降到了最低。
“推”的方式是指,Subject维护一份观察者的列表,每当有更新发生,Subject会把更新消息主动推送到各个Observer去。
“拉”的方式是指,各个Observer维护各自所关心的Subject列表,自行决定在合适的时间去Subject获取相应的更新数据。
“推”的好处包括:
1、高效。如果没有更新发生,不会有任何更新消息推送的动作,即每次消息推送都发生在确确实实的更新事件之后,都是有意义的。
2、实时。事件发生后的第一时间即可触发通知操作。
3、可以由Subject确立通知的时间,可以避开一些繁忙时间。
4、可以表达出不同事件发生的先后顺序。
“拉”的好处包括:
1、如果观察者众多,Subject来维护订阅者的列表,可能困难,或者臃肿,把订阅关系解脱到Observer去完成。
2、Observer可以不理会它不关心的变更事件,只需要去获取自己感兴趣的事件即可。
3、Observer可以自行决定获取更新事件的时间。
4、拉的形式可以让Subject更好地控制各个Observer每次查询更新的访问权限。
简单工厂
模式定义:
将变化从代码中抽离,将pizzastore中创建pizza的行为,包装到simplefactory中,这样实现类变化的分离,好处就是此时的简单工厂可以有很多的客户,在发生改变时,只需要修改简单工厂得代码,而不需要修改调用简单工厂得客户的代码。
将大量的if else 的创建实例的语句从pizzastore中抽离,将其放入一个工厂中。
工厂方法模式
模式需求
如果有不同风味的披萨需要实现,那么就需要很多的披萨工厂,但是每个工厂中的每个披萨的做法又不尽相同,固定的披萨制作方法的代码缺乏弹性。
1、客户端不知道它所需要的对象的类,在工厂方法模式中,客户端不需要具体产品类的类名,只需要知道所对应的工厂即可,具体产品对象由具体工厂类创建,可见具体产品类的类名在配置文件或者数据库中存在!
2、抽象工厂类通过其子类来指定创建那个产品类,用父类来新建子类可以提高可扩展性。
模式定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化哪一个,工厂方法让类把实例化推迟到子类。
模式优势
由于pizza对象是抽象的,orderpizza并不知道是哪些类参与了进来,这就是解耦。
当你在实例化一个对象的时候,就是在依赖于他的具体类。
设计原则
依赖倒置原则 :要依赖于抽象,不要依赖具体(不能让高层组件,依赖于底层组件,pizastore是高层组件,pizza的实现是底层组件,不管是高层组件还是底层组件,都应该依赖于抽像)。
避免
变量不可以包含具体类的引用。一旦new,就对具体类产生依赖,用工厂模式来避开。
2 类不要派生至具体类。用派生抽象类避开。
3 不要覆盖基类已经实现的方法。基类中已实现的方法应该由所有子类共享。
单件模式
模式定义
确保一个类只有一个实例,并提供一个全局的访问点。
模式应用
定义一个private static singleton类型的变量,定义一个私有的构造器,再定义一个共有的静态的获取该类的实例的方法,如果变量的值是null,就创建一个对象,并返回它,否则返回原本的对象。
模型优化
方法一:
加synchronized关键字,实现同步,缺点就是性能下降,因为每次只有第一次创建对象的时候才需要同步,以后每次只需要调用变量就可以,所以说同步是一定的累赘。
方法二:
直接在定义类型变量的时候就创建一个对象,getinstance方法只需要返回这个变量就行,缺点就是开销比较大,因为在类没有被用到的时候,就已经被创建,浪费空间。Private static S s=new S();
方法三:
双重加锁:
声明变量的时候加上volatile关键字,在getinstance方法中,先检查对象是否存在,不存在的话,就进入同步区域,synchronized(singleton.class)再进行判断是否存在,不存在则创建,否则。。。。。。
命令模式
模式定义
将请求封装成对象,以便将不同的请求,队列,日志来参数化其他对象,命令模式也支持撤销操作。
模式应用
解决命令请求者和命令实现者之间的耦合关系,解决这种耦合的好处主要有两点:
- 更方便的对命令进行扩展。
- 对命令进行统一的控制
模式理解
就是将请求的对象与实际实行的对象进行解耦,加一个中间的服务者,例如女招侍,女招侍的角色就相当于一个个的行为请求命令,而厨师就相当于行为的实际实施者,就是电器类,这样做的好处就是将命令请求者和命令实现者解耦,这样能够更方便的对命令进行扩展,更方便的对命令进行统一的控制。
模式应用
实现一个command的抽象类,所有的请求均继承自这个类,所有的请求类都拥有一个请求实现者的变量,请求类中的各个行为均是通过调用行为实现者的某个方法实现的。
模板方法模式
模式定义
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法可以使子类在不改变算法结构的前提下,重新定义算法中的某些步骤。
实现步骤
定义一个抽象类,将要封装的算法设置为final,使用钩子就是动态的进行调用某一个方法,比如客户要加糖,就判断是否加糖,if(加糖),调用加糖的方法,else 不调用任何方法。
模型优势
把不变的行为搬移到父类,去除了子类中重复的代码。
子类实现算法的某些细节,有利于算法的扩展。
通过父类调用子类的实现操作,通过扩展子类增添新的行为,符合开闭原则。
设计原则
好莱坞原则:
以通知代替轮询。
迭代器模式
模式定义
提供一种方法顺序访问一个集合对象中的各个元素,而又不暴露其内部的表示。
模式优势
可以顺序的访问集合中的每一个元素,而又不知道其内部是如何表示的,有一个统一的方法可以访问集合中的每一个对象,
设计原则
单一原则:
一个类应该只有一个变化的原因。
当我们允许一个类不仅要完成自己的事情,同时还要担任更多的责任时,我们就给了这个类两个变化的原因呢。一个责任应该只指派给一个类。
内聚:
用来衡量一个模块或者一个类紧密的达到单一的目的或者责任。
状态模式
模式定义:
允许对象在内部状态改变时改变他的行为,对象看起来好像修改了他的类。
与策略模式的区别
将一群行为封装在状态对象中,主类的行为随时可以委托到那些状态对象中的一个,随时间流逝,当前状态在对象集合中游走改变,以反映主类的内部状态,因此,主类的行为也会随之改变,但是客户对于主类的改变而浑然不知。
而对于策略模式来说,客户通常是指定主类所要组合的策略对象是那一个。
模式实现
定义一群状态对象,全部实现状态接口,状态接口中含有糖果机的所有行为,这样,这一群行为全部拥有了糖果机的所有行为,在这一群状态对象的内部实现各个行为的时候,只需要实现行为,并且跳转到另外一个状态即可。
定义一个糖果机类定义各个类的变量,在糖果机的构造器中new出相应的状态对象,初始化当前的糖果机状态变量为未投入钱,然后定义糖果机的各个行为,在行为内部,用糖果机的状态变量调用相应得行为。
设计原则
将变化抽离。
最小知识原则
一个类对自己所依赖的类知道的越少越好。对于被依赖的类来说,不管其内部如何复杂,都尽量的将逻辑封装在类的内部,对外除了提供public方法,不泄露任何信息。
还有更简单的定义,就是只与直接的朋友通信,直接的朋友指的是出现成员变量,方法参数,方法返回值的类。
如何遵守这个原则:
即在类的对象内,应该调用
I 该对象本身
ii作为参数传进来的对象
iii此方法创建或者实例化的对象
iv对象的任何组件
一个软件实体应该尽可能少的与其他实体发生交互作用。
当一个模块发生改变时,会尽量少的影响其他模块,实现了模块间的松散耦合,
应该尽量减少对象之间的交互,如果两个对象之间不彼此通信,那么两个对象之间应该不发生任何直接的相互作用,如果一个对象需要调用另一个对象的方法,可以通过第三者转发这个调用,通过合理的第三者降低对象间的耦合度。
MVC
Model-View-Controller
视图:
用来呈现模型,视图通常从模型中取得它需要显示的状态和数据。
控制器:
取得用户的输入并解读其对模型的意思。
模型:
模型持有所有的数据,状态和程序逻辑。模型没有注意到程序和控制器,虽然他提供了操纵和检索状态的接口,并发送状态改变通知给观察者。
- 用户和视图交互。
- 控制器要求模型作出改变。
- 控制器也可以要求视图作出改变
- 模型状态改变时会通知视图
- 视图像模型询问状态。
模型实现了观察者模式,当状态改变时,相关对象将持续更新。使用观察者模式可以让模型独立于视图和控制器,同一个模型可以拥有不同的视图,甚至可以拥有多个视图。
视图和控制器实现了经典的策略模式,视图是一个对象,可以被调整使用不同的策略,而控制器就提供了策略,视图只关心系统中可视的部分,对于任何界面行为,都会委托给控制器处理,使用策略模式可以让视图和模型之间的关系解耦,因为控制器负责和模型交互来传递用户的请求,对于工作是怎么完成的,用户毫不知情。