适配器模式,装饰模式,代理模式异同

菜鸟版JAVA设计模式—适配器模式,装饰模式,代理模式异同

一、概念

适配器模式,允许因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。
装饰器模式,原有的不能满足现有的需求,对原有的进行增强。
代理模式,同一个类而去调用另一个类的方法,不对这个方法进行直接操作。

适配器的特点在于兼容,从代码上的特点来说,适配类与原有的类具有相同的接口,并且持有新的目标对象。就如同一个三孔转2孔的适配器一样,他有三孔的插头,可以插到三孔插座里,又有两孔的插座可以被2孔插头插入。适配器模式是在于对原有3孔的改造。在使用适配器模式的时候,我们必须同时持有原对象,适配对象,目标对象。。。。

装饰器模式特点在于增强,他的特点是被装饰类和所有的装饰类必须实现同一个接口,而且必须持有被装饰的对象,可以无限装饰。

代理模式的特点在于隔离,隔离调用类和被调用类的关系,通过一个代理类去调用。

总的来说就是如下三句话:

  • 适配器模式是将一个类(a)通过某种方式转换成另一个类(b).
  • 装饰模式是在一个原有类(a)的基础之上增加了某些新的功能变成另一个类(b).
  • 代理模式是将一个类(a)转换成具体的操作类(b).
二、例子

先简单介绍一下,公司有一个ORDER系统,专门用于提供订单管理的接口,提供给O2O商城,WAP商城,手机类APP,微信等客户端调用。ORDER系统在上线之时,已经包含了非常完整的数据操作。

现手机类APP需要升级,老的接口可能不能满足需求,如原O2O订单提货延长有效期接口需要提供截至时间和订单号,新APP可能不提供截至时间,只需要提供订单号即可延长时间。而老的接口又不能修改,因为老的order接口是针对所有平台的,那么必须将新接口要求与原接口进行适配。。。

解决方案如下:新增AppAdepter类,用来适配老的接口,同时开发给新的接口。。。。

先给出原接口和实现类

/**
 * 原接口,需要传入orderId,时间
 *
 */
public interface SourceOrderApi {
    public void updateDate(String orderId,String date,String client);
}

public class SourceOrderApiImpl implements SourceOrderApi{
    @Override
    public void updateDate(String orderId, String date, String client) {
        System.out.println(client+"已将订单"+orderId+"的有效期延长至"+date);       
    }
}

public class Test {
    public static void main(String[] args) {
        SourceOrderApi sourceOrderApi = new SourceOrderApiImpl();
        sourceOrderApi.updateDate("123456", "2014-10-15", "user");
    }
}
//运行结果:user已将订单123456的有效期延长至2014-10-15

新的接口和实现类:

public interface AppOrderApi {
    //只需要传入订单Id即可
    public void updateDate(String orderId,String client);
}

public class AppOrderApiImpl implements AppOrderApi{
    SourceOrderApi sourceOrderApi;
    public AppOrderApiImpl(){
        sourceOrderApi = new SourceOrderApiImpl();
    }

    @Override
    public void updateDate(String orderId,String client) {
        //这里适配的方式随意,但是保证是要完全兼容原有的,就是保证调用原有的接口
        sourceOrderApi.updateDate(orderId, "9999-12-31",client);
    }
}

public class Test {
    public static void main(String[] args) {
        AppOrderApi appOrderApi = new AppOrderApiImpl();
        appOrderApi.updateDate("123456", "user");
    }
}
//运行结果:user已将订单123456的有效期延长至9999-12-31

在这套代码中,新的实现类持有了老接口的对象,就是把这个对象new 出来。。。然后在新的方法里,进行适配操作。而这里所谓的适配就是兼容老接口和兼容新接口。兼容老接口非常简单,就是直接调用老的方法即可。而兼容新接口就是你所要去做的业务逻辑。。。比如我这里做了比较简单的操作,app类的统一传入“9999-12-31”,这些都是根据具体的项目需求去实现你的业务代码。看到这,很多人会觉得 这样的代码是不是很常见。。。。我自己都特意去翻了一下我之前的代码,很多类似的写法。。。其实设计模式很多时候都融入到我们的代码中,只是我们没有去理解这种模式,所以就算你自己写出来了,都不知道这是一种适配器模式。。。

那么再回头来说代理模式,在代码上,和适配器模式有着相似的地方!

再比如,现在我们公司的系统又要进行升级,我们原先的接口没有加入安全机制,导致了任何人都可以随意调用这个接口,现在公司需要对这个接口进行改造,只其只能被admin这个客户端调用,其他用户一律要输入账号密码才能调用。那么上面原接口和类不需要改动,我们只需要新增代理器即可。。。

这里就会显出代理模式和适配器模式最大的区别,代理模式是与原对象实现同一个接口,而适配器类则是匹配新接口,说白了,实现一个新的接口。


public class ProxySourceOrderApiImpl implements SourceOrderApi {
    SourceOrderApi sourceOrderApiImpl;
    public ProxySourceOrderApiImpl(){
        sourceOrderApiImpl = new SourceOrderApiImpl();
    }

    @Override
    public void updateDate(String orderId, String date, String client) {
        //进行判断,如果是admin则更新否则让其输入账号密码
        if("admin".equals(client)){
            sourceOrderApiImpl.updateDate(orderId, date, client);
        }else{
            System.out.println("账号不是admin,没有查询权限,请输入以admin操作");
        }
    }
}

这里的代理类必须要持要实现原接口和持有原接口的对象,才能称之为代理类。

这样,我们不需要修改原先的实现类,用一个代理类来进行过滤。有些人可能有这样的疑惑,为什么不直接在原实现类中修改,记住JAVA设计模式的基本原则,对内关闭修改。

假如你并没有对方的类,别人只是提供给你这样一个可以操作的JAR包你如何去做?把JAR包反编译,再修改?又假如某些地方可以直接调用原有接口,你如果修改原有的实现类,岂不是对其他的地方也造成了影响?不能修改原有代码这是基本原则。

最后,就是装饰器模式,装饰器模式与相对于上面2种模式更好理解,差别也最大。

假如说,现在这个延长订单,不光可以延长订单提货有效期,可以延长订单的退货有效期。

这就是一个典型的装饰器,你需要做的是丰富原接口的功能,并且不改动原先的接口。


public class NewSourceOrderApiImpl implements SourceOrderApi {

    SourceOrderApi sourceOrderApi;
    public NewSourceOrderApiImpl(SourceOrderApi sourceOrderApi){
        this.sourceOrderApi = sourceOrderApi;
    }
    @Override
    public void updateDate(String orderId, String date, String client) {
        sourceOrderApi.updateDate(orderId, date, client);
        System.out.println(client+"已将订单"+orderId+"的退款期延长至"+date);       
        
    }

}

在装饰器模式中,必须要有被装饰的类和装饰的类。。在这套代码中,原先SourceOrderApi的对象就是被装饰的类,而新建NewSourceOrderApiImpl 就是装饰类,装饰类必须把被装饰的对象当作参数传入。

这就是和代理模式的代码不同之处,代理模式一定是自身持有这个对象,不需要从外部传入。而装饰模式的一定是从外部传入,并且可以没有顺序,按照代码的实际需求随意挑换顺序,就如你吃火锅先放白菜还是先放丸子都可以。

再从使用上来看,代理模式注重的是隔离限制,让外部不能访问你实际的调用对象,比如权限控制,装饰模式注重的是功能的拓展,在同一个方法下实现更多的功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容