Java設計模式——代理模式

來源:互聯網
上載者:User

Java設計模式——代理模式
前言:

上一篇說到了策略模式。單類圖上來說,它和本篇要說的代理模式還真是有些像似。都需要一個公用的介面,還有一些實作類別。代理類(封裝類)封裝了一個介面對象,提供用戶端調用。這些都很類似。不過,有一個細節需要我們注意一下,那就是這裡的代理類也需要去繼承這裡的公用介面。而在策略模式中,封裝類則不需要這麼做。

概述:

代理模式就是定義一個原對象的代理對象,來協助原對象和系統之外的業務作溝通。也就是說,如果我們不能直接或是不願直接去使用原對象,那麼我們就可以使用建立一個原對象的代理來進行操作。

模式說明:舉例--話題訪問1.背景

現在我們假設我們要構建一個網站。這個網站允許三類使用者訪問,分別是:普通註冊成員、站長管理員、遊客。

那麼這個時候,各個不同的訪問者對某一網頁的內容都有不同的許可權。比如,普通註冊成員可以訪問、發表和評論(回複)一個話題;站長管理員可以訪問、發表、評論以及刪除一個話題;而遊客則只能訪問這個網頁。

2.類圖

圖-1 代理模式類圖

根據上面例子中的需求,我們可以畫出圖-1中的類圖。不過雖然類圖中的三個實作類別都有實現介面中所有方法,不過其實這些實現方法卻不適合所有的訪問者對象。比如,Member雖然有remove方法,不過普通會員並不能真的刪除一個話題。所以這個控制就十分有必要了。

3.代碼及說明:1.公用介面

在公用介面中需要定義一些訪問者的基本行為。分別是訪問話題、發表話題、評論話題和刪除話題。

 

public interface Visitor {    public void visit() throws RoleExcption;        public void publish() throws RoleExcption;        public void comment() throws RoleExcption;        public void remove() throws RoleExcption;}

 

2.具體實作類別

本例中具體實作類別倒沒什麼太多的內容,只是重寫了實現介面中的方法。

 

public class Manager implements Visitor {    @Override    public void visit() {        System.out.println("我是網站的管理員,我訪問了這個主題");    }    @Override    public void publish() {        System.out.println("我是網站的管理員,我發表了一個主題");    }    @Override    public void comment() {        System.out.println("我是網站的管理員,我評論了一個主題");    }    @Override    public void remove() {        System.out.println("我是網站的管理員,我刪除了一個主題");    }}

 

3.代理類

代理類的作用還是比較重要,和必要的。他們負責來控制一個訪問者對話題的行為,防止越權的行為。比如一個遊客訪問者是不能發表和評論話題的。那麼可以通過代理中方法作控制方式來實現。如下:

 

public class ProxyVisitor implements Visitor {    private Visitor visitor = null;        public ProxyVisitor() {        // 預設情況是遊客        visitor = new Tourist();    }        public ProxyVisitor(Visitor _visitor) {        visitor = _visitor;    }        @Override    public void visit() throws RoleExcption {        visitor.visit();    }    @Override    public void publish() throws RoleExcption {        if (visitor instanceof Tourist) {            throw new RoleExcption("遊客不能發表主題,請先註冊帳號");        }                visitor.publish();    }    @Override    public void comment() throws RoleExcption {        if (visitor instanceof Tourist) {            throw new RoleExcption("遊客不能發表評論,請先註冊帳號");        }                visitor.comment();    }    @Override    public void remove() throws RoleExcption {        if (!(visitor instanceof Manager)) {            throw new RoleExcption("只有管理員才可以刪除主題");        }                visitor.remove();    }}

 

4.用戶端

這裡我們通過不同的訪問者進行不同的操作,觀察結果。

 

public class VisitorClient {    public static void main(String[] args) {        Manager manager = new Manager();        Member member = new Member();        Tourist tourist = new Tourist();                ProxyVisitor visitor = null;        System.out.println("------------------- 1 --------------------");        try {            visitor = new ProxyVisitor(manager);            visitor.visit();            visitor.publish();            visitor.comment();            visitor.remove();        } catch (RoleExcption e) {            System.err.println(e);        }        ThreadUtils.sleep(50);                System.out.println("------------------- 2 --------------------");        try {            visitor = new ProxyVisitor(member);            visitor.visit();            visitor.publish();            visitor.comment();            visitor.remove();        } catch (RoleExcption e) {            System.err.println(e);        }        ThreadUtils.sleep(50);                System.out.println("------------------- 3 --------------------");        try {            visitor = new ProxyVisitor(tourist);            visitor.visit();            visitor.publish();            visitor.comment();            visitor.remove();        } catch (RoleExcption e) {            System.err.println(e);        }    }}

 

5.測試結果 圖-2 網站訪問代理測試結果

 

舉例--學生考試1.背景

我們都經曆過學生時代,也都有考過試,當然也都有作過弊(什嗎?你沒有作過弊?那當我沒說...)。

學生考試是一個公開的行為,而學生作弊卻不能公開。所以,我們的考試方法是公有的,而作弊卻是私人的。可是,如果我們的用戶端程式需要我們在考試的時候來作一下弊。要怎麼辦呢?你可能會說,這好辦,反射啊。的確是這樣的,是要用到反射。不過這個反射我們封裝在了代理類裡面了,再從代理類裡把這個方法打成公開的方法。在下面的類圖中也會體現。

2.類圖

這個類圖跟上面話題訪問者的類圖很像。不過還是有一個地方不一樣,發現了沒有?那就是實作類別中有一個比介面類中多出的方法cheat(作弊),且是一個私人的方法,不過在代理類裡,這個方法被打成了公開的了。

圖-3 代理模式類圖

3.代碼及說明1.公用介面

說明同上

 

public interface Student {    public void examinate();        public void announce();    }

 

2.具體實作類別

 

說明同上

 

public class SeniorStudent implements Student {    private String name = "";    private int score = 0;        public SeniorStudent(String _name) {        name = _name;    }        @Override    public void examinate() {        score = NumberUtils.randomInteger(40, 150);    }    @SuppressWarnings("unused")    private void cheat() {        System.out.println(name + "正在作弊...噓...");        score += (NumberUtils.randomInteger(150 - score));    }    @Override    public void announce() {        System.out.println(name + "考了" + score + "分");    }}

 

3.代理類

注意看這裡的cheat方法,是一個公開的方法。在這個方法裡,使用了Java的反射來實現對具體實作類別的私人方法進行訪問。

 

public class StudentProxy implements Student {    private Student student = null;    public StudentProxy(Student _student) {        student = _student;    }    @Override    public void examinate() {        student.examinate();    }    @Override    public void announce() {        student.announce();    }    public void cheat() throws ClassNotFoundException, NoSuchMethodException,            SecurityException, IllegalAccessException, IllegalArgumentException,            InvocationTargetException {        Class  clazz = Class.forName(student.getClass().getName());        Method method = clazz.getDeclaredMethod("cheat");        method.setAccessible(true);        method.invoke(student);    }}

 

4.用戶端

說明同上

 

public class StudentProxyClient {    public static void main(String[] args) {        StudentProxy proxy = new StudentProxy(new Pupil("小明"));        proxy.examinate();        proxy.announce();        try {            proxy.cheat();        } catch (ClassNotFoundException | NoSuchMethodException                | SecurityException | IllegalAccessException                | IllegalArgumentException | InvocationTargetException e) {            e.printStackTrace();        }        proxy.announce();    }}

 

5.測試結果

圖-4 學生考試代理測試結果

GitHub源碼下載:

https://github.com/William-Hai/DesignPattern-Proxy

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.