设计模式总结1. 单例模式: 实现方式: a) 将被实现的类的构造方法设计成private的。 b) 添加此类引用的静态成员变量,并为其实例化。 c) 在被实现的类中提供公共的CreateInstance函数,返回实例化的此类,就是b中的静态成员变量。
应用场景: 优点:
2. 策略模式: 实现方式: a) 提供公共接口或抽象类,定义需要使用的策略方法。(策略抽象类) b) 多个实现的策略抽象类的实现类。(策略实现类) c) 环境类,对多个实现类的封装,提供接口类型的成员量,可以在客户端中切换。 d) 客户端 调用环境类 进行不同策略的切换。 注:Jdk中的TreeSet和 TreeMap的排序功能就是使用了策略模式。 策略模式的优点(1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。 (2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。 策略模式的缺点(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。 (2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
3. 代理模式: 实现方式: a) 为真实类和代理类提供的公共接口或抽象类。(租房) b) 真实类,具体实现逻辑,实现或继承a。(房主向外租房) c) 代理类,实现或继承a,有对b的引用,调用真实类的具体实现。(中介) d) 客户端,调用代理类实现对真实类的调用。(租客租房) 二)动态代理 实现方式: a) 公共的接口(必须是接口,因为Proxy类的newproxyinstance方法的第二参数必须是个接口类型的Class) b) 多个真实类,具体实现的业务逻辑。 c) 代理类,实现InvocationHandler接口,提供Object成员变量,和Set方法,便于客户端切换。 d) 客户端,获得代理类的实例,为object实例赋值,调用Proxy.newproxyinstance方法在程序运行时生成继承公共接口的实例,调用相应方法,此时方法的执行由代理类实现的Invoke方法接管。 jdk动态代理使用的局限性:
4. 观察者模式: 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。 实现方式: a) 角色抽象类(提供对观察者的添加,删除和通知功能)。 b) 角色具体类,实现a,维护一个c的集合(对角色抽象类的实现)。 c) 观察者抽象类(被角色通知后实现的方法)。 d) 观察者实现类,实现c(多个)。 注:JDK提供了对观察者模式的支持,使用Observable类和Observer接口 两种模型(推模型和拉模型): ■ 推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值。 ■ 推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是主题对象本身,这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。
5. 装饰模式: 实现方式: a) 抽象的被装饰角色 (所有的角色都要直接或间接的实现本角色) b) 具体的被装饰角色,实现或继承a (被功能扩展的角色) c) 装饰角色,实现或继承a (本类有对a的引用,所有的具体装饰角色都需要继承这个角色) d) 多个具体修饰角色 ,继承c(对被装饰角色的功能扩展,可以任意搭配使用) 意图: 动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。 适用环境: (1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。 (2)处理那些可以撤消的职责。 (3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的 子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
6. 适配器模式: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。 1. 类适配器(子类继承方式) 实现方式: a) 目标抽象角色(定义客户要用的接口) b) 适配器(实现a继承c,作为一个转换器被客户调用) c) 待适配器(真正需要被调用的) d) 客户端(借用a的实例调用c的方法) 2. 对象适配器(对象的组合方式) 实现方式: a) 目标抽象角色(定义客户要用的接口) b) 适配器(实现a,维护一个c的引用,作为一个转换器被d调用) c) 待适配器(真正需要被调用的) d) 客户端(此类,借用a类的实例调用c类的方法,类似静态代理,但是解决的问题不同) 3. 缺省的方式 实现方式: a) 抽象接口 b) 实现a的适配器类(空实现) c) 客户端,继承b,调用b中的方法,不必直接实现a(直接实现a需要实现a中的所有的方法) 适配器模式的优点:1. 更好的复用性 系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。 2. 更好的扩展性 在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。 适配器模式的缺点:过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
7. 命令模式 将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或记录日志,以及支持可撤销的操作 将“发出请求的对象”和”接收与执行这些请求的对象”分隔开来。 实现方式: a) 抽象的命令角色 , 如:菜单(规定可以点哪些菜) b) 具体的命令角色(实现a 维护一个对c的引用),如:订单(已点的菜) c) 接收者(具体执行命令的角色),实际操作时,很常见使用"聪明"命令对象,也就是直接实现了请求,而不是将工作委托给c (弊端?) 如:厨师接收订单后做菜 d) 调用者(维护一个对a的引用),如:服务员负责点菜并把订单推给厨师 e) 客户端 调用d发出命令进而执行c的方法,如:顾客点餐
效果: 8. 组合模式 将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和复杂对象的使用具有一致性。 实现方式: a) 抽象的构件接口 (规范执行的方法),b及c都需实现此接口,如:Junit中的Test接口 b) 叶部件(实现a,最小的执行单位),如:Junit中我们所编写的测试用例 c) 组合类(实现a并维护一个a的集合[多个b的组合]),如:Junit中的 TestSuite d) 客户端 可以随意的将b和c进行组合,进行调用
什么情况下使用组合模式: 当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。
9. 简单工厂模式 就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。 实现方式: a) 抽象产品类(也可以是接口) b) 多个具体的产品类 c) 工厂类(包括创建a的实例的方法)
优点: 工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。
缺点: 由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;
10. 模板方法模式 实现方式: a) 父类模板类(规定要执行的方法和顺序,只关心方法的定义及顺序,不关心方法实现) b) 子类实现类(实现a规定要执行的方法,只关心方法实现,不关心调用顺序)
优点: 1)封装不变部分,扩展可变部分:把认为不变部分的算法封装到父类实现,可变部分则可以通过继承来实现,很容易扩展。 2)提取公共部分代码,便于维护。 3)行为由父类控制,由子类实现。 缺点: 模板方法模式颠倒了我们平常的设计习惯:抽象类负责声明最抽象、最一般的事物属性和方法,实现类实现具体的事物属性和方法。在复杂的项目中可能会带来代码阅读的难度。
|
|