结构类模式大PK

装饰模式VS代理模式

  首先要说明的是装饰模式是代理模式的特殊应用,两者的共同点是有相同的接口,不同点事代理模式着重对代理过程的控制,而装饰模式则是对类的功能进行加强或减弱,着重类功能的变化。我们看看两者的类图吧!就是一模一样只是代理类和装饰类的名字不一样了而已。我们通过代理类和装饰类看看二者的区别吧。

//代理模式还是侧重于对代理过程的控制,是否允许功能的执行
public class SingerAgent{
private Singer singer;
public SingerAgent(Singer singer){
this.singer = singer;
}
public void singing(){
Random rand = new Random();
if(rand.nextBoolean()){
System.out.println("代理人同意歌手唱歌");
singer.sing();
}else{
System.out.println("代理人不同意歌手唱歌");
}
}
}
//装饰模式侧重于对装饰对象功能的增强或者减弱
public class SingerWithJet{
private Singer singer;
public SingerWithJet(Singer singer){
this.singer = singer;
}
public void singing(){
System.out.println("歌手的舞蹈优美");
singer.sing();
}
}

  代理模式是把当前行为或功能委托给其它对象执行,代理类负责接口限定:是否可以调用真实角色,以及是否对发送到真实角色的消息进行变形处理,它不对主题角色的功能做任何处理,保证原汁原味的调用。代理模式的极致就是AOP,采用Spring框架必然要使用的技术,它就是使用了代理和反射的技术。

装饰模式是在要保证接口不变的情况下加强对象的功能,它保证的是被修饰对象功能比原始对象更加丰富,但是不做准入条件和准入参数的判断,是否可以执行类的功能,过滤输入参数是否符合规则等都不是装饰模式关系的内容。

装饰模式VS适配器模式

  装饰模式和适配器模式在类图的设计上差别比较大,但是他们的功能有很多相似的地方,都能够实现包装的作用,通过委托方式实现功能。不同点是:装饰模式包装的是自己的兄弟类,隶属于同一个家族(相同接口或父类),适配器模式则修饰非血缘关系的类,把一个非本家族对象伪装成一个本家族的对象,而对象的本质还是非相同接口的对象。我们还是以丑小鸭的故事来说明这个问题吧。

  首先,我们看看装饰模式实现丑小鸭变白天鹅类图实现。

public interface Swan {
public void fly(); //飞行能力
public void cry(); //叫声
public void desAppearance(); //外表
} public class UglyDuckling implements Swan{ @Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("丑小鸭小时候不会飞");
} @Override
public void cry() {
// TODO Auto-generated method stub
System.out.println("咕噜...咕噜");
} @Override
public void desAppearance() {
// TODO Auto-generated method stub
System.out.println("小时候外形是脏兮兮的白色,毛茸茸的大脑袋");
} } public class Decorator implements Swan{
private Swan swan;
public Decorator(Swan swan){
this.swan = swan;
}
@Override
public void fly() {
// TODO Auto-generated method stub
swan.fly();
} @Override
public void cry() {
// TODO Auto-generated method stub
swan.cry();
} @Override
public void desAppearance() {
// TODO Auto-generated method stub
swan.desAppearance();
}
protected Swan getSwan(){
return this.swan;
} } public class BeautifulAppearance extends Decorator{ public BeautifulAppearance(Swan swan) {
super(swan);
// TODO Auto-generated constructor stub
}
public void desAppearance(){
super.getSwan().desAppearance();
System.out.println("纯白色的外表,非常惹人喜爱!");
}
} public class StrongBehavior extends Decorator{ public StrongBehavior(Swan swan) {
super(swan);
// TODO Auto-generated constructor stub
}
public void fly(){
super.getSwan().fly();
System.out.println("长大后的丑小鸭变白天鹅会飞了");
}
} public class Client { /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Swan duck = new UglyDuckling();
duck.cry();
duck.fly();
duck.desAppearance();
duck = new BeautifulAppearance(duck);
duck = new StrongBehavior(duck);
duck.cry();
duck.fly();
duck.desAppearance();
}
}

  装饰模式实现丑小鸭的蜕变,关注对象功能的强化,是对原始对象的行为和属性的修正和加强,把原本被人视为歧视、冷落的丑小鸭通过两次强化处理最终转变为收人喜爱、羡慕的白天鹅。

  但是通过适配器解决丑小鸭变白天鹅的问题就有点不一样了,我们得把丑小鸭伪装成鸭类,得让她实现鸭类的接口,表现鸭类的行为特征,但是经过时间的推移,丑小鸭终究会变成白天鹅,从而表现出天鹅的特征。为此,需要丑小鸭类继承自天鹅类,从而也实现鸭类的接口。其通用类图如下:鸭类的接口有会叫(void cry())、外观(desAppearance())、其他表现(desBehavior()),天鹅接口有鸣叫、飞翔、以及外观。

public interface IDuck {
public void cry(); //叫声
public void desAppearance(); //外观
public void desBehavior(); //其他表现
} public interface ISwan {
public void cry();
public void desAppearance();
public void fly();
} public class WhiteSwan implements ISwan{ @Override
public void cry() {
// TODO Auto-generated method stub
System.out.println("咕噜...咕噜...");
} @Override
public void desAppearance() {
// TODO Auto-generated method stub
System.out.println("纯白色的羽毛,非常惹人喜爱!");
} @Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("会飞翔");
} } public class UglyDuckling extends WhiteSwan implements IDuck{ @Override
public void desBehavior() {
// TODO Auto-generated method stub
System.out.println("会游泳");
super.fly();
} public void cry() {
super.cry();
}
public void desAppearance() {
super.desAppearance();
} } public class Client { /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
IDuck uglyDuckling = new UglyDuckling();
uglyDuckling.cry();
uglyDuckling.desAppearance();
uglyDuckling.desBehavior();
} }

  采用适配器模式讲述丑小鸭变天鹅的故事,我们首先观察到的是鸭和天鹅的不同点,建立了不同的接口以实现不同的物种,然后在需要的时候把一个物种伪装成另一个物种,实现不同物种的相同处理过程,这就是适配器模式。

  • 最佳实践
    • 意图不同,装饰模式的意图是加强对象的功能,例子中是把一个自卑的丑小鸭变成一个自信的白天鹅,它不改变类的行为和属性,只是增加功能,而适配器模式则关注的是转化,它的主要意图是两个不同对象之间的转化,它可以把一个天鹅转化为小鸭子看待,也可以把一只小鸭子看成小天鹅,其实就是关注类之间的转化啦。
    • 施与对象不同,装饰对象必须是自己的同宗,也就是相同的接口或父类,只要在具有相同的属性和行为的情况下,才能比较行为是增加还是减弱;适配器模式则必须是不同的两个对象,因为它侧重转化,只有两个不同的对象才有转化的必要。
    • 场景不同,装饰模式在任何时候都可以使用,只要是想增强类的功能,而适配器模式则是一个补救模式,一般出现在系统成熟或已将构建完毕的项目中,作为一个紧急处理手段采用。
    • 扩展性不同,装饰模式很容易扩展,如果不需要装饰,直接去掉装饰类就可以,而且可以继续增加新的装饰类;而适配器模式相当于在两个不同对象之间架起了一座沟通的桥梁,需要从系统整体考虑是否能够撤销。

设计模式之结构类模式大PK的更多相关文章

  1. 设计模式之行为类模式大PK

                                        行为类模式大PK 行为类模式包括责任链模式.命令模式.解释器模式.迭代器模式.中介者模式.备忘录模式.观察者模式.状态模式.策略 ...

  2. 设计模式之创建类模式大PK

                                        创建类模式大PK 创建类模式包括工厂方法模式.建造者模式.抽象工厂模式.单例模式和原型模式,他们能够提供对象的创建和管理职责.其 ...

  3. 设计模式之结构类模式PK

    结构类模式包括: 适配器模式 桥梁模式 组合模式 装饰模式 门面模式 享元模式 代理模式 结构类模式着重于如何建立一个软件结构 为什么叫结构类模式呢? 因为他们都是通过组合类或对象产生更大结构以适应更 ...

  4. 创建类模式大PK(总结)

    创建类模式包含工厂方法模式.建造者模式.抽象工厂模式.单例模式和原型模式,它们都可以提供对象的创建和管理职责.当中的单例模式和原型模式很easy理解,单例模式是要保持在内存中仅仅有一个对象,原型模式是 ...

  5. 第28章 行为型模式大PK

    27.1 策略模式 VS 命令模式 27.1.1 策略模式实现压缩算法 //行为型模式大PK——策略模式和命令模式 //实例:用策略模式实现压缩算法 #include <iostream> ...

  6. 第27章 结构型模式大PK

    27.1 代理模式 VS 装饰模式 27.1.1 代理模式 (1)场景:客人找运动员代理要求安排运动员参加比赛 (2)说明:代理人有控制权,可以拒绝客人的要求,也可以答应安排,甚至自己下去跑(因为有些 ...

  7. 第26章 创建型模式大PK

    26.1 工厂方法模式 VS 建造者模式 26.1.1 按工厂方法建造超人 (1)产品:两类超人,成年超人和未成年超人. (2)工厂:这里选择简单工厂 [编程实验]工厂方法建造超人 //创建型模式大P ...

  8. 设计模式之行为类模式PK

    行为类模式包括: 责任链模式 命令模式 解释器模式 迭代器模式 中介者模式 备忘录模式 观察者模式 状态模式 策略模式 模板方法模式 访问者模式 行为型模式涉及到算法和对象间职责的分配 行为类模式关注 ...

  9. 设计模式之创建类模式PK

    创建类模式包括: 工厂方法模式 建造者模式 抽象工厂模式 单例模式 原型模式 创建类模式能够提供对象的创建和管理职责. 其中单例模式和原型模式非常容易理解, 单例模式是要保持在内存中只有一个对象,原型 ...

随机推荐

  1. 【前端性能】高性能滚动 scroll 及页面渲染优化

    最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作. 本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的 ...

  2. ubuntu如何安装nodejs最新版 本

    如何正确的安装nodejs? 我们可以先安装nvm, git clone https://github.com/creationix/nvm.git ~/.nvm 然后打开 ~/.bashrc ,   ...

  3. Android公共title的应用

    我们在开发Android应用中,写每一个页面的时候都会建一个title,不是写一个LinearLayout就是写一个RelativeLayout,久而久之就会觉得这样繁琐,尤其几个页面是只是标题不一样 ...

  4. 小兔Java教程 - 三分钟学会Java文件上传

    今天群里正好有人问起了Java文件上传的事情,本来这是Java里面的知识点,而我目前最主要的精力还是放在了JS的部分.不过反正也不麻烦,我就专门开一贴来聊聊Java文件上传的基本实现方法吧. 话不多说 ...

  5. 【Java每日一题】20170106

    20170105问题解析请点击今日问题下方的"[Java每日一题]20170106"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  6. JAVA回调机制解析

    一.回调机制概述     回调机制在JAVA代码中一直遇到,但之前不懂其原理,几乎都是绕着走.俗话说做不愿意做的事情叫做突破,故诞生了该文章,算是新年的新气象,新突破!     回调机制是什么?其实回 ...

  7. Android之文件数据存储

    一.文件保存数据介绍 Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的.文件可用来存放大量数据,如文本.图 ...

  8. svn常用命令

    1.新建版本库 [root@localhost repos]# mkdir -p project [root@localhost repos]# svnadmin create project [ro ...

  9. MySQL: Fabric 搭建 HA

    搭建好Fabric之后,就可以在它的基础上创建HA Group. Shard Group.HA+Shard Group等.这里来说明一下如何快速的搭建HA环境. Fabric 192.168.2.23 ...

  10. MongoDB学习笔记三—增删改文档上

    插入insert 单条插入 > db.foo.insert({"bar":"baz"}) WriteResult({ }) 批量插入 > db.fo ...