• <menu id="gyiem"><menu id="gyiem"></menu></menu>
  • <menu id="gyiem"><code id="gyiem"></code></menu>

    Java設計模式(六) 代理模式 vs. 裝飾模式

    原創文章,轉載請務必將下面這段話置于文章開頭處(保留超鏈接)。
    本文轉發自技術世界原文鏈接 http://www.luozeyang.com/design_pattern/proxy_decorator/

    模式介紹

    • 代理模式(Proxy Pattern),為其它對象提供一種代理以控制對這個對象的訪問。
    • 裝飾模式(Decorator Pattern),動態地給一個對象添加一些額外的職責。

    從語意上講,代理模式的目標是控制對被代理對象的訪問,而裝飾模式是給原對象增加額外功能。

    類圖

    代理模式類圖如下
    Proxy pattern class diagram

    裝飾模式類圖如下
    Decorator pattern class diagram

    從上圖可以看到,代理模式和裝飾模式的類圖非常類似。下面結合具體的代碼講解兩者的不同。

    代碼解析

    本文所有代碼均可從作者Github下載

    相同部分

    代理模式和裝飾模式都包含ISubject和ConcreteSubject,并且這兩種模式中這兩個Component的實現沒有任何區別。

    ISubject代碼如下

    1
    2
    3
    4
    5
    6
    7
    package com.jasongj.subject;

    public interface ISubject {

    void action();

    }

    ConcreteSubject代碼如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.jasongj.subject;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;


    public class ConcreteSubject implements ISubject {

    private static final Logger LOG = LoggerFactory.getLogger(ConcreteSubject.class);

    @Override
    public void action() {
    LOG.info("ConcreteSubject action()");
    }

    }

    代理類和使用方式

    代理類實現方式如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    package com.jasongj.proxy;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import java.util.Random;

    import com.jasongj.subject.ConcreteSubject;
    import com.jasongj.subject.ISubject;

    public class ProxySubject implements ISubject {

    private static final Logger LOG = LoggerFactory.getLogger(ProxySubject.class);

    private ISubject subject;

    public ProxySubject() {
    subject = new ConcreteSubject();
    }

    @Override
    public void action() {
    preAction();
    if((new Random()).nextBoolean()){
    subject.action();
    } else {
    LOG.info("Permission denied");
    }
    postAction();
    }

    private void preAction() {
    LOG.info("ProxySubject.preAction()");
    }

    private void postAction() {
    LOG.info("ProxySubject.postAction()");
    }

    }

    從上述代碼中可以看到,被代理對象由代理對象在編譯時確定,并且代理對象可能限制對被代理對象的訪問。

    代理模式使用方式如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.jasongj.client;

    import com.jasongj.proxy.ProxySubject;
    import com.jasongj.subject.ISubject;

    public class StaticProxyClient {

    public static void main(String[] args) {
    ISubject subject = new ProxySubject();
    subject.action();
    }

    }

    從上述代碼中可以看到,調用方直接調用代理而不需要直接操作被代理對象甚至都不需要知道被代理對象的存在。同時,代理類可代理的具體被代理類是確定的,如本例中ProxySubject只可代理ConcreteSubject。

    裝飾類和使用方式

    裝飾類實現方式如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package com.jasongj.decorator;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import com.jasongj.subject.ISubject;

    public class SubjectPreDecorator implements ISubject {

    private static final Logger LOG = LoggerFactory.getLogger(SubjectPreDecorator.class);

    private ISubject subject;

    public SubjectPreDecorator(ISubject subject) {
    this.subject = subject;
    }

    @Override
    public void action() {
    preAction();
    subject.action();
    }

    private void preAction() {
    LOG.info("SubjectPreDecorator.preAction()");
    }

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package com.jasongj.decorator;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import com.jasongj.subject.ISubject;

    public class SubjectPostDecorator implements ISubject {

    private static final Logger LOG = LoggerFactory.getLogger(SubjectPostDecorator.class);

    private ISubject subject;

    public SubjectPostDecorator(ISubject subject) {
    this.subject = subject;
    }

    @Override
    public void action() {
    subject.action();
    postAction();
    }

    private void postAction() {
    LOG.info("SubjectPostDecorator.preAction()");
    }

    }

    裝飾模式使用方法如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.jasongj.client;

    import com.jasongj.decorator.SubjectPostDecorator;
    import com.jasongj.decorator.SubjectPreDecorator;
    import com.jasongj.subject.ConcreteSubject;
    import com.jasongj.subject.ISubject;

    public class DecoratorClient {

    public static void main(String[] args) {
    ISubject subject = new ConcreteSubject();
    ISubject preDecorator = new SubjectPreDecorator(subject);
    ISubject postDecorator = new SubjectPostDecorator(preDecorator);
    postDecorator.action();
    }

    }

    從上述代碼中可以看出,裝飾類可裝飾的類并不固定,并且被裝飾對象是在使用時通過組合確定。如本例中SubjectPreDecorator裝飾ConcreteSubject,而SubjectPostDecorator裝飾SubjectPreDecorator。并且被裝飾對象由調用方實例化后通過構造方法(或者setter)指定。

    裝飾模式的本質是動態組合。動態是手段,組合是目的。每個裝飾類可以只負責添加一項額外功能,然后通過組合為被裝飾類添加復雜功能。由于每個裝飾類的職責比較簡單單一,增加了這些裝飾類的可重用性,同時也更符合單一職責原則。

    總結

    • 從語意上講,代理模式是為控制對被代理對象的訪問,而裝飾模式是為了增加被裝飾對象的功能
    • 代理類所能代理的類完全由代理類確定,裝飾類裝飾的對象需要根據實際使用時客戶端的組合來確定
    • 被代理對象由代理對象創建,客戶端甚至不需要知道被代理類的存在;被裝飾對象由客戶端創建并傳給裝飾對象

    Java設計模式系列

    郭俊 Jason wechat
    歡迎關注作者微信公眾號【大數據架構】
    您的贊賞將支持作者繼續原創分享
    速赢彩app 镇江 | 牡丹江 | 泗阳 | 三亚 | 启东 | 本溪 | 赣州 | 鹤岗 | 海拉尔 | 临夏 | 库尔勒 | 喀什 | 惠州 | 天水 | 博尔塔拉 | 广元 | 铜川 | 陇南 | 建湖 | 武安 | 宁国 | 鸡西 | 广州 | 安顺 | 清远 | 克拉玛依 | 高雄 | 安岳 | 简阳 | 镇江 | 云南昆明 | 淮北 | 明港 | 库尔勒 | 东方 | 金华 | 南平 | 宜春 | 河源 | 山东青岛 | 大连 | 大丰 | 博尔塔拉 | 海门 | 宜昌 | 沧州 | 通化 | 肥城 | 东方 | 宿迁 | 湖南长沙 | 锡林郭勒 | 西藏拉萨 | 无锡 | 临夏 | 玉溪 | 广汉 | 吉林 | 浙江杭州 | 铁岭 | 焦作 | 内蒙古呼和浩特 | 义乌 | 东台 | 枣庄 | 蓬莱 | 项城 | 梧州 | 忻州 | 姜堰 | 招远 | 克拉玛依 | 益阳 | 湘西 | 包头 | 临海 | 山东青岛 | 宁波 | 黄冈 | 盐城 | 吐鲁番 | 白银 | 承德 | 崇左 | 宿州 | 雅安 | 通辽 | 灌南 | 如皋 | 正定 | 霍邱 | 临夏 | 天水 | 余姚 | 六安 | 武夷山 | 汕尾 | 柳州 | 扬州 | 吕梁 | 丽江 | 垦利 | 平潭 | 包头 | 高雄 | 延边 | 廊坊 | 广西南宁 | 资阳 | 甘孜 | 迪庆 | 平凉 | 金坛 |