国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

代理模式

2019-11-14 23:19:47
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
代理模式

本文講述了代理模式,包括了普通代理、強(qiáng)制代理和動(dòng)態(tài)代理。

原文鏈接:

http://tianweili.github.io/blog/2015/03/13/PRoxy-pattern/

介紹

代理模式屬于結(jié)構(gòu)性模式,使用頻率很高。

定義:Provide a surrogate or placeholder for another object to control access to it.為其他對(duì)象提供一種代理以控制這個(gè)對(duì)象的訪問(wèn)。

裝飾模式、狀態(tài)模式、策略模式、訪問(wèn)者模式本質(zhì)上都是在更特殊的場(chǎng)合采用了代理模式。

UML類圖

{% img /design-pattern/proxy-pattern-uml.png %}

從以上UML類圖中可以看出代理模式主要有三種角色:

抽象主題角色

可以是接口或抽象類,是某類通用業(yè)務(wù)的定義。

具體主題角色

作為被代理對(duì)象,是具體業(yè)務(wù)的真實(shí)執(zhí)行者。

代理主題角色

是具體主題對(duì)象的代理,負(fù)責(zé)對(duì)具體對(duì)象的應(yīng)用,把所有抽象主題定義的方法委托給具體主題對(duì)象來(lái)實(shí)現(xiàn),它用來(lái)在具體主題對(duì)象業(yè)務(wù)處理的前后做一些處理工作。

代碼示例
/** * Abstract subject class. */public interface Subject {    public void someMethod();}/** * Real subject class. */public class RealSubject implements Subject {    private String name;    public RealSubject(String name) {        this.name = name;    }    @Override    public void someMethod() {        System.out.println(name + "'s someMehtod.");    }}/** * Proxy class. */public class ProxySubject implements Subject {    private Subject subject;    public ProxySubject(Subject subject) {        this.subject = subject;    }    @Override    public void someMethod() {        this.before();        subject.someMethod();        this.after();    }    /**     * preprocessing     */    private void before() {        // do something...    }        /**     * follow-up processing     */    private void after() {        // do something...    }}

從以上代碼可以看出ProxySubject對(duì)象還有before和after方法,可以在RealSubject對(duì)象的someMethod業(yè)務(wù)方法前后做一些預(yù)處理和善后處理工作。

一個(gè)代理類可以代理多個(gè)被代理對(duì)象,只要是實(shí)現(xiàn)同一個(gè)接口。當(dāng)然也可以一個(gè)被代理對(duì)象就有一個(gè)代理類,不過(guò)一般是一個(gè)接口有一個(gè)代理類就夠了,在應(yīng)用時(shí)具體是代理哪一個(gè)被代理對(duì)象,這是由場(chǎng)景類也就是高層模塊定義的,根據(jù)構(gòu)造方法的傳入哪一個(gè)被代理對(duì)象參數(shù)來(lái)決定代理哪一個(gè)對(duì)象。

構(gòu)造方法:

public ProxySubject(Subject subject) {    this.subject = subject;}

想代理哪個(gè)對(duì)象就要傳入生成這個(gè)對(duì)象的實(shí)例。

優(yōu)點(diǎn)

各個(gè)角色職責(zé)清晰,比如被代理對(duì)象只需要實(shí)現(xiàn)屬于自己具體的業(yè)務(wù)邏輯就行了,不用去關(guān)心非本職責(zé)的業(yè)務(wù)處理。其他的一些處理業(yè)務(wù)可以交給代理類來(lái)處理。這樣做的好處是編程簡(jiǎn)潔清晰,業(yè)務(wù)分明。

擴(kuò)展性好,具體實(shí)現(xiàn)對(duì)象的業(yè)務(wù)發(fā)生了變化,只需要修改自身業(yè)務(wù)處理邏輯,或者增加刪減一個(gè)實(shí)現(xiàn)業(yè)務(wù)接口的對(duì)象,不會(huì)影響代理業(yè)務(wù)。

代理模式可以提供非常好的訪問(wèn)控制,由代理類來(lái)控制被代理對(duì)象,可以做一些預(yù)處理消息,過(guò)濾消息,消息轉(zhuǎn)發(fā)和善后處理工作等等。

普通代理和強(qiáng)制代理

普通代理和強(qiáng)制代理是代理模式的兩種不同結(jié)構(gòu),是根據(jù)調(diào)用者能夠訪問(wèn)到代理對(duì)象還是具體對(duì)象來(lái)區(qū)分的。就好比網(wǎng)絡(luò)上的代理服務(wù)器設(shè)置分為普通代理和透明代理。普通代理需要用戶手動(dòng)設(shè)置代理服務(wù)器的ip地址,用戶必須知道代理的存在。透明代理就是用戶不需要設(shè)置代理服務(wù)器地址,就可以直接訪問(wèn),不用知道代理的存在。

普通代理

普通代理是用戶只能訪問(wèn)代理角色,而不能訪問(wèn)真實(shí)角色。

只需要對(duì)上面代碼稍作改動(dòng)即可實(shí)現(xiàn)普通代理的效果,代碼如下:

/** * Abstract subject class. */public interface Subject {    public void someMethod();}/** * Real subject class. */public class RealSubject implements Subject {    private String name;    /**     * Don't allow client call this.     */    public RealSubject(Subject subject, String name) throws Exception {        if(subject == null) {            throw new Exception("Don't allow realSubject created!");        } else {            this.name = name;        }    }    @Override    public void someMethod() {        System.out.println(name + "'s someMehtod.");    }}/** * Proxy class. */public class ProxySubject implements Subject {    private Subject subject;    /**     * Client call proxy subject.     */    public ProxySubject(String name) {        try {            this.subject = new RealSubject(this, name);        } catch (Exception e) {            e.printStackTrace();        }    }    @Override    public void someMethod() {        this.before();        subject.someMethod();        this.after();    }    /**     * preprocessing     */    private void before() {        // do something...        System.out.println("before ...");    }        /**     * follow-up processing     */    private void after() {        // do something...        System.out.println("after ...");    }}public class Client {    public static void main(String[] args) {        Subject subject = new ProxySubject("ZhangSan");        subject.someMethod();    }}

運(yùn)行程序結(jié)果如下:

before ...ZhangSan's someMehtod.after ...

在上面RealSubject的構(gòu)造方法中是通過(guò)傳入?yún)?shù)subject來(lái)限制用戶不能實(shí)例化自己,當(dāng)然也可以通過(guò)別的一些限制條件,比如類名必須有Proxy等等。

強(qiáng)制代理

普通代理是通過(guò)代理角色找到真是角色,而強(qiáng)制代理是強(qiáng)制只能通過(guò)真實(shí)角色查找代理角色來(lái)訪問(wèn),想直接通過(guò)實(shí)例化代理角色或真實(shí)角色都不能訪問(wèn)。

UML類圖如下:

{% img /design-pattern/proxy-pattern-uml-2.png %}

從以上UML類圖可以看出Subject接口中添加了個(gè)獲取代理的接口方法。

代碼清單:

/** * Abstract subject class. */public interface Subject {    public void someMethod();    public Subject getProxy();}/** * Real subject class. */public class RealSubject implements Subject {    private String name;    private Subject proxy;    public RealSubject(String name) {        this.name = name;    }    @Override    public void someMethod() {        if (this.isProxy()) {            System.out.println(name + "'s someMehtod.");        } else {            System.out.println("Only visit proxy class is allowed!");        }    }    @Override    public Subject getProxy() {        // appoint proxy class.        this.proxy = new ProxySubject(this);        return proxy;    }    private boolean isProxy() {        if (this.proxy == null) {            return false;        } else {            return true;        }    }}/** * Proxy class. */public class ProxySubject implements Subject {    private Subject subject;    public ProxySubject(Subject subject) {        this.subject = subject;    }    @Override    public void someMethod() {        subject.someMethod();    }    @Override    public Subject getProxy() {        return this;    }}

當(dāng)客戶端想通過(guò)真實(shí)角色來(lái)訪問(wèn)時(shí),客戶端代碼如下:

public class Client {    public static void main(String[] args) {        Subject realSubject = new RealSubject("ZhangSan");        realSubject.someMethod();    }}

執(zhí)行結(jié)果:

Only visit proxy class is allowed!

訪問(wèn)被拒絕,因?yàn)樗峭ㄟ^(guò)真實(shí)角色來(lái)直接訪問(wèn)的,而不是通過(guò)真實(shí)角色來(lái)獲取代理角色來(lái)訪問(wèn)。

當(dāng)客戶端想通過(guò)代理角色來(lái)訪問(wèn)時(shí),客戶端代碼如下:

public class Client {    public static void main(String[] args) {        Subject realSubject = new RealSubject("ZhangSan");        Subject proxy = new ProxySubject(realSubject);        proxy.someMethod();    }}

執(zhí)行結(jié)果:

Only visit proxy class is allowed!

訪問(wèn)同樣被拒絕,因?yàn)樗峭ㄟ^(guò)代理角色來(lái)直接訪問(wèn)的,而不是通過(guò)真實(shí)角色來(lái)獲取代理角色來(lái)訪問(wèn)。

只有強(qiáng)制客戶端通過(guò)真實(shí)角色來(lái)獲取代理對(duì)象,才能訪問(wèn)??蛻舳舜a如下:

public class Client {    public static void main(String[] args) {        Subject realSubject = new RealSubject("ZhangSan");        Subject proxy = realSubject.getProxy();        proxy.someMethod();    }}

執(zhí)行結(jié)果:

ZhangSan's someMehtod.

通過(guò)真實(shí)角色來(lái)獲取代理對(duì)象訪問(wèn)成功。

動(dòng)態(tài)代理

這一節(jié)之前所講的代理其實(shí)都是靜態(tài)代理,它有一個(gè)特點(diǎn)就是要在實(shí)現(xiàn)階段就要指定代理類以及被代理者,很不靈活。而動(dòng)態(tài)代理就是在實(shí)現(xiàn)階段不用管代理具體對(duì)象,而在運(yùn)行階段指定代理哪個(gè)對(duì)象即可生產(chǎn)代理對(duì)象。

基本的UML類圖如下所示:

{% img /design-pattern/proxy-pattern-uml-3.png %}

從類圖中可以看出,具體的業(yè)務(wù)邏輯和代理邏輯是兩條線,兩者之間沒(méi)有必然的耦合關(guān)系。

InvocationHandler是JDK提供的接口,用來(lái)對(duì)被代理類的方法進(jìn)行代理。

注意:被代理者必須實(shí)現(xiàn)一個(gè)接口,否則動(dòng)態(tài)代理無(wú)法生成代理對(duì)象。

動(dòng)態(tài)代理是根據(jù)被代理者的接口生成所有的方法。通過(guò)InvocationHandler接口,所有被代理的方法都由InvocationHandler來(lái)接管實(shí)際的處理邏輯。

代碼清單:

/** * Abstract subject class. */public interface Subject {    public void someMethod();}/** * Real subject class. */public class RealSubject implements Subject {    private String name;    public RealSubject(String name) {        this.name = name;    }    @Override    public void someMethod() {        System.out.println(name + "'s someMehtod.");    }}import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {    private Object obj;    public MyInvocationHandler(Object obj) {        this.obj = obj;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("before...");        Object result = method.invoke(obj, args);        System.out.println("after...");        return result;    }}

invoke方法是接口InvocationHandler中定義必須實(shí)現(xiàn)的,它用來(lái)完成對(duì)真實(shí)方法的調(diào)用。

客戶端調(diào)用代碼:

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class Client {    public static void main(String[] args) {        Subject subject = new RealSubject("ZhangSan");                ClassLoader loader = subject.getClass().getClassLoader();        Class[] interfaces = subject.getClass().getInterfaces();        InvocationHandler handler = new MyInvocationHandler(subject);                Subject proxy = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);        proxy.someMethod();    }}

執(zhí)行結(jié)果:

before...ZhangSan's someMehtod.after...

從結(jié)果中可以看出我們已經(jīng)達(dá)到了代理RealSubject對(duì)象的目的。

看了上面的客戶端調(diào)用代碼,我們可以優(yōu)化一下,將Proxy封裝起來(lái),使得調(diào)用更簡(jiǎn)便一些。增加動(dòng)態(tài)代理封裝類:

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class DynamicProxy {        public static Object newProxyInstance(Object object) {                ClassLoader loader = object.getClass().getClassLoader();        Class[] interfaces = object.getClass().getInterfaces();        InvocationHandler handler = new MyInvocationHandler(object);                return Proxy.newProxyInstance(loader, interfaces, handler);    }}

客戶端調(diào)用:

public class Client {    public static void main(String[] args) {        Subject subject = new RealSubject("ZhangSan");        Subject proxy = (Subject) DynamicProxy.newProxyInstance(subject);        proxy.someMethod();    }}
動(dòng)態(tài)代理優(yōu)點(diǎn)

動(dòng)態(tài)代理?yè)碛幸陨响o態(tài)代理所有優(yōu)點(diǎn),除此之外還有動(dòng)態(tài)代理的代理對(duì)象是在需要的時(shí)候動(dòng)態(tài)生成的。

在業(yè)務(wù)邏輯開(kāi)發(fā)時(shí)可以不用管代理業(yè)務(wù)邏輯,這兩條線不會(huì)耦合。比如在做具體的業(yè)務(wù)邏輯設(shè)計(jì)和實(shí)現(xiàn)時(shí)不用考慮日志、事務(wù)、權(quán)限等邏輯處理,這些可以通過(guò)動(dòng)態(tài)代理來(lái)搞定。

Struts2的Form映射和Spring的AOP(aspect Oriented Programming)就是動(dòng)態(tài)代理的典型應(yīng)用。

作者:李天煒

原文鏈接:http://tianweili.github.io/blog/2015/03/13/proxy-pattern/

轉(zhuǎn)載請(qǐng)注明作者和文章出處,謝謝。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 北宁市| 台湾省| 神农架林区| 青海省| 淳安县| 南澳县| 长岛县| 石台县| 军事| 北川| 东乡族自治县| 叶城县| 大方县| 潞西市| 西乌| 临沂市| 拉孜县| 闽侯县| 双牌县| 莱阳市| 项城市| 大新县| 天峻县| 武功县| 精河县| 蓬溪县| 平塘县| 苍南县| 陈巴尔虎旗| 浮梁县| 镶黄旗| 南木林县| 原阳县| 苍山县| 长宁县| 元朗区| 东台市| 扶余县| 屏南县| 庄浪县| 新河县|