设计模式结构模式
Posted Nothing Is Given.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式结构模式相关的知识,希望对你有一定的参考价值。
GOF论述了23种设计模式,它们有3个分类————创建型模式、结构型模式、行为模式。
此篇为结构型模式
结构型模式所所关注的问题是:如何将类和对象进行组合以便获取功能更加庞大的结构?
一般情况下,结构型模式都是使用继承机制将接口进行组合以及实现。
导入问题:使用继承的缺点
|-----对象的继承关系在编译时就已经确定,所以运行时子类无法改变从父类继承来的实现,即子类对父类有很强的依赖性。
|-----继承所带来的子类与父类的强依赖关系限制了复用性和程序的灵活性。
***************************************************************************
合成/聚合复用原则
|-----尽量使用合成/聚合,尽量不要使用继承。
|-----聚合表示一种“弱拥有”关系,
|-----合成表示一种“强拥有”关系,严格的整体与部分的关系,它们具有相同的生命周期。
***************************************************************************
桥接模式————将抽象部分与它的实现部分分离,使它们都可以独立地变化。
|-----实现部分指的是抽象类和它的派生类用来实现自己的对象,例如,课程既可以按照课程类别来分类,也可以按照系所来区分。
|-----桥接模式适用于这种有多重分类并且每种分类都需要独立变化的情况。
|-----从效果上来说,解除了不同分类的实现之间的耦合,使其可以独立地变化。
适用场景:
|-----当不希望在抽象和它的实现之间有一个固定的绑定关系时。
|-----当类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充时。
|-----当对一个抽象类的实现部分的修改应对客户端不产生影响时。
***************************************************************************
适配器模式(Adapter Pattern)————将一个类的接口转换成客户希望的另外一个接口。
|-----也称为包装或者包装样式,使原本由于接口不兼容而不能一起工作的那些类可以一起工作。
|-----当需要复用一些现存的类但其接口与复用环境不一致时,适配器模式拥有很高的价值。
实际问题:
在实际的软件开发项目中,经常会遇到以前编写的模块的接口跟当前设计的模块接口不吻合以至于无法复用的情况。这种情况在项目中需要使用第三方组件时也尤为突出
所以这里讨论的主题是,如何在不该写原有模块的基础上,快速地使其适应新的项目。
GOF的设计模式中,适配器模式有两种类型————类适配器模式和对象适配器模式,类适配器模式需要用到多继承,但是Java没有多继承。所以重点介绍对象适配器模式。
二者的区别:
|-----对象适配器,通过对象组合的方式来进行处理,比较灵活;
|-----类适配器,通过继承的方法来实现,将旧系统的方法进行封装。灵活性较差
|-----对象适配器在进行适配器之间的转换过程时,使用类适配器也能完成,但是依赖性会变大,并且根据适配要求的灵活性,可能通过继承系统会膨胀到难以控制。
适用场景:
|-----当想要使用一个已经存在的类,但是该类的接口不符合现有的需求时。
|-----当需要创建一个可以被复用的类,该类能够与其他无关的类甚至无法预见的类协同工作时。
|-----当需要使用一些已经存在的子类,但是不可能对所有的都进行子类化以匹配它们的接口时,对象适配器可以对其父类接口进行适配。
***************************************************************************
装饰模式
问题导入:
当对一个类的功能进行扩展时,程序员会往类里面增加新的方法。通常,我们可以通过添加子类的方式增加对象的功能。
当需要在运行时生成一个具有新行为的对象时,即动态扩展某个对象的功能,装饰模式就很有价值。
装饰模式————动态地给一个对象添加一些额外的职责
|-----就增加功能来说,装饰模式比生成子类更为灵活。
|-----如果一个类反复多次地被装饰模式增加功能,那么程序员就应该考虑重构这个类。(尤其是通过装饰模式添加的功能甚至比初始时的功能更多时)
|-----装饰模式始终只起到装饰作用,被装饰的类的核心功能仍然是主干。
适用场景:
|-----当需要以不影响其他对象为前提实现动态、透明地给单个对象添加职责时。
|-----当需要对象的某些职责进行撤销操作时。
|-----当不能用生成子类的方法进行当前系统的扩充时。
***************************************************************************
组合模式
享元模式
外观模式
***************************************************************************
代理模式————为其它对象提供一种代理以控制这个对象的访问。
|-----当程序员希望截获程序中发给某个对象的消息甚至分布式地处理时,都可以使用代理模式来解决实际会遇到的问题。
|-----代理对象会提供一个接口,这个接口与它所代理的源对象提供的接口是几乎完全一样的。
|-----当其他对象向源对象发出请求命令时,代理对象就将这些请求命令转发给自己所代理的对象。
优点:
|-----权限的控制,可以通过多个代理对象来控制用户对一个具有非常多的敏感功能的对象的访问。
缺点:
|-----由于请求命令经过了两次转发,所以其中任意一次出响异常都会导致程序无法正常工作。
|-----代理对象和被代理对象之间是紧耦合关系,所以在实际应用中,如果有其他可以完成工作的更可靠的方式,一般不会选择代理模式。
代理模式的使用场景:
|-----当需要为一个对象在不同的地址空间提供局部代表时;
|-----当需要创建开销非常大的对象时;
|-----当需要控制对原始对象的访问时;
|-----当需要在访问对象时执行一些附加操作时,比如可以通过代理对象计算访问实际对象的次数;
J2SE中的动态代理
|-----J2SE中的静态代理就是使用这里的“代理模式”来实现,通过代理类来封装某个实现类,加强实现类的某个方法的功能,而不必改变原有的源代码。
|-----JDK中的动态代理中的代理类是由java.lang.reflect.Proxy类在运行期间根据接口的定义,采用Java反射功能动态生成。
|-----和java.lang.reflect.InvocationHandler结合,可以加强现有类的方法实现。
|-----自定义的Handler需要实现invoke方法,该方法可以使用Java反射调用实现类的实现方法,同时可以实现其他功能,例如在调用实现类方法前后加入Log。
|-----而Proxy类根据Handler和需要代理的接口动态生成一个接口实现类的对象,当用户调用这个动态生成的实现类时,实际上是调用了自定义Handler的invoke方法。
动态代理的实现步骤:
1、新建生成动态代理对象类,实现java.lang.reflect.InvocationHandler接口;
2、新建一个方法用于生成代理对象并返回该对象;
3、实现接口方法invoke,一般会将额外的操作置于此处;
以上是关于设计模式结构模式的主要内容,如果未能解决你的问题,请参考以下文章