對象結構型模式

對象結構型模式

結構型模式(Structural Pattern)描述如何將類或者對象結合在一起形成更大的結構

適配器模式

在適配器模式中可以定義一個包裝類,包裝不兼容接口的對象,這個包裝類指的就是適配器(Adapter),它所包裝的對象就是適配者 (Adaptee),即被適配的類。適配器提供客戶類需要的接口,適配器的實現就是把客戶類的請求 轉化爲對適配者的相應接口的調用。適配器可以使由於接口不兼容而不能交互的類可以一起工作。這就是適配器模式的模式動機。

簡單的說,需要實現一個接口,這個接口的功能已經有一個類實現,但這個類卻不符合接口的規則,因此使用適配器Adapter包裝適配者Adaptee(可以有多個Adaptee),調用Adaptee的方法進行二次封裝到Adapter的方法中,使用者調用Adapter的方法,並不關心適配器如何實現,反正Adapter對外能夠提供功能即可

模式定義 :適配器模式(Adapter Pattern) :將一個接口轉換成客戶希望的另一個接口,適配器模式使接口不兼容的那些類可以一起工作。

適配器的核心在於使用新的類實現舊接口,老接口不能輕易動,新的實現類不符合老接口的規則,因此使用適配器實現老接口,調用新類的方法,相當於對各種實現類進行統合,對外能夠通過統一的舊接口提供功能。

img

Outlet提供電壓,AC plug插不進去,使用Adapter進行中間轉化,使用者可以利用多態使用AC plug返回一個Adapter,Adapter調用Outlet提供電壓。

M3LtmV.md.png

適配器模式有三種實現方式:

類適配器

Adapter繼承功能類實現老接口,通過super調用方法

@Configuration
public class SpringConfiguration {
    @Bean
    public Outlet220V outlet220V(){
        return new Outlet220V();
    }

    @Bean(name="adapterA")
    public AdapterA adapterA(){
        return new AdapterA();
    }
}
public interface Outlet5V {
    //提供5V電壓
    int outlet5V();
}
//新的實現類,能提供220V電壓
public class Outlet220V {
    public int outlet220V(){
        System.out.println("我被適配器調用,我能輸出220V電壓");
        return 220;
    }
}
//類適配器
public class AdapterA extends Outlet220V implements Outlet5V {
    @Override
    public int outlet5V(){
        System.out.println("我是類適配器,繼承實現類,實現老接口");
        return super.outlet220V()/44;
    }
}

public class AdapterPatternTest {
    public static void main(String[] args){
        ApplicationContext context= new AnnotationConfigApplicationContext(SpringConfiguration.class);

        Outlet5V outlet5V=(AdapterA)context.getBean("adapterA",AdapterA.class);
        outlet5V.outlet5V();
    }
}

對象適配器

內部維護實現對象,調用實現方法實現老接口:

public class AdapterB implements Outlet5V{

    private Outlet220V outlet220V=new Outlet220V();

    public int outlet5V(){
        System.out.println("我是對象適配器,內部維護功能對象,調用實現方法實現老接口");
        return outlet220V.outlet220V()/44;
    }
}

接口適配

介紹完類適配器和對象適配器,我們再來看看接口適配器,接口適配器相對類適配器和對象適配器而言,接口適配器相對更加靈活,就好比手機適配器中的萬能適配器,不管接入的是多少伏的電源,最終都能保證輸出電源爲5V。

首先,定義一個總的抽象類,並且給予一個默認值(或者直接是接口,目的都是爲了定義功能),即提供總的抽象

public abstract class AbstractAdapter {
    public int output(){
        return 220;
    }
}

基於該抽象類重寫方法,提供不同的功能

public class Outlet110V extends AbstractAdapter {
    @Override
    public int output(){
        return 110;
    }
}
public class Outlet440V extends AbstractAdapter {
    @Override
    public int output(){
        return 440;
    }
}

適配器內部維護一個總的抽象對象,提供不同的構造器,提供setter,實現老接口時,必須能判斷當前維護的抽象對應的具體實現是哪一個,可使用instanceof或者反射

public class AdapterC implements Outlet5V {
    private AbstractAdapter abstractAdapter;
    public AdapterC(AbstractAdapter abstractAdapter){
        this.abstractAdapter=abstractAdapter;
    }

    //這裏是接口適配器,內部維護總的抽象,可以是接口,也可以是抽象類,對外提供方法,因此必須有辦法判斷
    //具體是哪一個實現,可使用instanceof,也可以使用反射讀取信息
    @Override
    public int outlet5V(){
        System.out.println("我是接口適配器,內部維護一個總抽象,根據instanceof判斷當前是哪一個實現");
        if(abstractAdapter instanceof  Outlet110V)return abstractAdapter.output()/22;
        else if(abstractAdapter instanceof Outlet440V)return abstractAdapter.output()/88;
        return 5;
    }
}

橋接模式

將抽象部分與它的實現部分分離,使它們都可以獨立地變化。將抽象化(Abstraction)與實現化 (Implementation)脫耦,使得二者可以獨立地變化。

假設有兩個接口A與B,A有6個具體實現,B有4個具體實現,現在必須組合A,B以提供組合式的更強的功能,共有6*4=24個具體提供,爲實現解耦,現在將某一個接口抽象化,將A變爲抽象類,內部維護一個B並提供setter,A的具體實現都要繼承A,因爲A內部維護一個B並提供setter,因此A不關心具體的B是哪一個,調用功能即可,只需6+4=10個具體提供。

模式結構 :

• Abstraction:抽象類,內部維護一個Implementor並提供setter

• RefinedAbstraction:擴充抽象類

• Implementor:實現類接口

• ConcreteImplementor:具體實現類

McFXVO.md.png

抽象化角色和實現化角色可以以繼承的方式獨立擴展而互不影響,在程序運行時可以動態將一個抽象化子類的對象和一個實現化子類的對象進行組合,即系統需要對抽象化角色和實現化角色進行動態耦合。

• 一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。

• 對於那些不希望使用繼承或因爲多層次繼承導致系統類的個數急劇增 加的系統,橋接模式尤爲適用。

//實現接口與具體實現
public interface VideoStream {
    public void videoStream();
}
public class AVIVideoStream implements VideoStream {
    @Override
    public void videoStream(){
        System.out.println("提供AVI視頻流");
    }
}
public class MP4VideoStream implements VideoStream {
    @Override
    public void videoStream(){
        System.out.println("提供mp4視頻流");
    }
}
//抽象類與擴充實現
public abstract class VideoPlay {
    private VideoStream videoStream;
    public VideoPlay(VideoStream stream){
        this.videoStream=stream;
    }
    public VideoStream getVideoStream(){
        return videoStream;
    }

    public void play(){
    }
}
public class Aplay extends VideoPlay {
    public Aplay(VideoStream stream){
        super(stream);
    }
    @Override
    public void play(){
        System.out.println("獲取視頻流");
        super.getVideoStream().videoStream();
        System.out.println("A play");
    }
}
public class Bplay extends VideoPlay {
    public Bplay(VideoStream videoStream){
        super(videoStream);
    }

    @Override
    public void play(){
        System.out.println("獲取視頻流");
        super.getVideoStream().videoStream();
        System.out.println("B play");
    }
}
public class BridagePatternTest  {
    public static void main(String[] args){
        VideoPlay play=new Aplay(new AVIVideoStream());
        play.play();

        play=new Aplay(new MP4VideoStream());
        play.play();

        play=new Bplay(new AVIVideoStream());
        play.play();

        play=new Bplay(new MP4VideoStream());
        play.play();
    }
}
/*
獲取視頻流
提供AVI視頻流
A play
獲取視頻流
提供mp4視頻流
A play
獲取視頻流
提供AVI視頻流
B play
獲取視頻流
提供mp4視頻流
B play
*/

組合模式

組合模式描述瞭如何將容器對象和葉子對象進行遞歸組合,使得用戶在使用時無須對它們進行區分,可以一致地對待容器對象和葉子對象,組合多個對象形成樹形結構以表示“整體-部分”的結構層次。

模式結構:

• Component: 抽象構件

• Leaf: 葉子構件

• Composite: 容器構件

• Client: 客戶類

也就是整體與部分的模式,極其類似於文件與文件夾,文件夾裏面可以有子文件夾,也可以有文件,對於這樣的抽象樹形結構,定義一個抽象構件Component,客戶端調用抽象構件,這個抽象構件可以是文件也可以是文件夾,如果是文件(Leaf)直接執行操作,如果是文件夾(Composite)則調用內部維護的抽象構件

Component列表遞歸遍歷。

MfOxMV.md.png

即定義一個公共抽象類,該公共抽象的子類可以是具體實現,也可以是抽象容器,是容器的話內部就需要維護抽象類的集合列表以供遍歷

//公共抽象Component
public abstract class File {
    public abstract void read();
    public abstract void write();

    public abstract void add(File file);
    public abstract void remove(File file);
}
//具體實現
public class TextFile extends File {

    @Override
    public void read(){
        System.out.println("讀文本文件");
    }
    @Override
    public void write(){
        System.out.println("寫文本文件");
    }

    @Override
    public  void add(File file){

    }
    @Override
    public void remove(File file){

    }
}

public class VideoFile extends File{
    @Override
    public void read(){
        System.out.println("讀視頻文件");
    }
    @Override
    public void write(){
        System.out.println("寫視頻文件");
    }

    @Override
    public  void add(File file){

    }
    @Override
    public void remove(File file){

    }
}
//抽象容器,可繼續遞歸
public class Folder extends File {

    //維護文件列表
    private List<File> fileList=new ArrayList<>();

    @Override
    public void read(){
    }
    @Override
    public void write(){
    }

    @Override
    public  void add(File file){
        fileList.add(file);
    }
    @Override
    public void remove(File file){
        fileList.remove(file);
    }

    public List<File> getFileList(){
        return fileList;
    }
}
public class CompositePatternTest {

    public static void main(String[] args){
        Folder folder=new Folder();
        Folder subfolder=new Folder();
        subfolder.add(new TextFile());

        folder.add(new VideoFile());
        folder.add(subfolder);

        dfs(folder);
    }

    public static void dfs(File file){
        if(file instanceof Folder){
            for(File file1:((Folder) file).getFileList()){
                dfs(file1);
            }
        }
        file.read();
    }
}

組合模式非常適用於可遞歸描述的樹形數據結構,如目錄解析,XML解析

可以清楚地定義分層次的複雜對象,表示對象的全部或部分層次,使得增加新構件也更容易。 定義了包含葉子對象和容器對象的類層次結構,葉子對象可以被組合成更復雜的容器對象,而這個容器對象又可以被組合,這樣不斷遞歸下去,可以形成複雜的樹形結構。缺點就是變得更加抽象,很難對新增構件的類型進行限制。

裝飾模式

一般有兩種方式可以實現給一個類或對象增加行爲:

• 繼承機制,使用繼承機制是給現有類添加功能的一種有效途徑, 通過繼承一個現有類可以使得子類在擁有自身方法的同時還擁有父類的方法。但是這種方法是靜態的,用戶不能控制增加行爲的方式和時機。

• 關聯機制,即將一個類的對象嵌入另一個對象中,由另一個對象來決定是否調用嵌入對象的行爲以便擴展自己的行爲,我們稱這個嵌入的對象爲裝飾器(Decorator)。

裝飾模式可以在不需要創造更多子類的情況下,將對象的功能加以擴展。裝飾者內部維護原始對象,通過構造方法或者setter進行注入,對原始對象的方法進行重寫改造,提供增強後的功能,即成爲包裝器Wrapper。客戶端通過調用裝飾器以獲得原始對象增強後的功能,Java.io中的BufferInputStream等緩衝流是典型的裝飾器模式。

模式結構:

• Component: 抽象構件

• ConcreteComponent: 具體構件

• Decorator: 抽象裝飾類

• ConcreteDecorator: 具體裝飾類

MquB5t.md.png

在單一職責原則下,一個類不宜實現過多的功能,一個類能提供其基本功能,但在某些條件下又需要實現一些擴展功能,此時便可以使用繼承或者裝飾器模式,在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。 裝飾器內部維護原始對象,增加邏輯以增加功能。

public interface Cipher {
    String encrypt(String plainText);
}
/**
 * 自由實現,只提供簡單加密
 */
public class SimpleCipher implements Cipher {

    @Override
    public String encrypt(String plainText){
        StringBuilder res=new StringBuilder();
        for(char c:plainText.toCharArray()){
            res.append((int) c);
        }
        return res.toString();
    }
}
/**
 * 裝飾器,增強功能
 */
public class CipherDecorator implements Cipher {
    private Cipher cipher;
    public CipherDecorator(Cipher cipher){
        this.cipher=cipher;
    }

    public void setCipher(Cipher cipher) {
        this.cipher = cipher;
    }

    @Override
    public String encrypt(String plainText){
        return cipher.encrypt(plainText);
    }

    public String complexEncrypt(String plainText){
        StringBuilder res=new StringBuilder(encrypt(plainText));
        res.reverse();
        return res.toString();
    }

}
public class DecoratorPatternTest {
    public static void main(String[] args){
        Cipher cipher=new SimpleCipher();
        System.out.println(cipher.encrypt("HelloWorld"));

        CipherDecorator cipherDecorator=new CipherDecorator(cipher);
        System.out.println(cipherDecorator.complexEncrypt("HelloWorld"));

    }
}
/*結果爲
7210110810811187111114108100
0018014111117811180180110127
*/

裝飾模式與繼承關係的目的都是要擴展對象的功能,但是裝飾模式可以提供比繼承更多的靈活性。

• 可以通過一種動態的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的裝飾器,從而實現不同的行爲。

• 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行爲的組合。可以使用多個具體裝飾類來裝飾同一對象,得到功能更爲強大的對象。

• 具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構件類和具體裝飾類,在使用時再對其進行組合,原有代碼無須改變,符合“開閉原則”。

裝飾模式的缺點

• 使用裝飾模式進行系統設計時將產生很多小對象,這些對象的區別在於它們之間相互連接的方式有所不同,而不是它們的類或者屬性值有所不同,同時還將產生很多具體裝飾類。這些裝飾類和小對象的產生將增加系統的複雜度,加大學習與理解的難度。

• 這種比繼承更加靈活機動的特性,也同時意味着裝飾模式比繼承更加易於出錯,排錯也很困難,對於多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較爲煩瑣。

外觀模式

外部與一個子系統的通信必須通過一個統一的外觀對象進行,爲子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。又稱爲門面模式。

MOg9lq.md.png

模式結構:

• Facade: 外觀角色

• SubSystem:子系統角色

引入一個外觀對象,爲子系統提供統一入口,即提供一個統一的訪問門面,Facade內部維護子對象,通過方法返回系統,客戶端不用顯式聲明,而是通過該門面進行中間調用

public class Fan {
    public void on(){
        System.out.println("風扇開");
    }
    public void off(){
        System.out.println("風扇關");
    }
}
public class Light {
    public void on(){
        System.out.println("燈開");
    }
    public void off(){
        System.out.println("燈關");
    }
}
public class Facade {
    private Fan fan=new Fan();
    private Light light=new Light();

    public Fan getFan() {
        return fan;
    }

    public Light getLight() {
        return light;
    }
}
public class FacadePatternTest {
    public static void main(String[] args){
        Facade facade=new Facade();
        facade.getFan().on();
        facade.getLight().on();
    }
}
/*
風扇開
燈開
*/

外觀模式主要優點在於對客戶屏蔽子系統組件,減少了客戶處理的對象數目並使得子系統使用起來更加容易,它實現了子系統與客戶之間的松耦合關係。

其缺點在於不能很好地限制客戶使用子系統類,而且在不引入抽象外觀類的情況下,增加新的子系統可能需要修改外觀類或客戶端的源代碼,違背了“開閉原則”。 外觀模式適用情況包括:要爲一個複雜子系統提供一個簡單接口;客戶程序與多個子系統之間存在很大的依賴性;在層次化結構中,需要定義系統中每一層的入口,使得層與層之間不直接產生聯繫。

享元模式

即Flyweight Pattern,將具有相同性質的某個成員集合稱爲共享內容,如字母a-z都是字母,組合起來就是一個具有抽象共同特徵的集合,外部使用時需要這些細顆粒度的元素組合成一個新的對象(字符串),爲避免系統消耗,創建一個享元工廠,內部維護一個享元池,這個享元池就是細顆粒度的集合,當需要字母時通過工廠獲取,工廠先判斷池中是否有字母,如果存在直接返回就好,如果不存在則創建並返回。

劃分顆粒度,將共享內容維護在一個池,外部使用時先判斷池中有沒有,有則返回,沒有則創建並返回,享元模式的目的就是使用共享技術來實現大量細粒度對象的複用,享元工廠與享元池是其核心。

MvooYq.md.png

模式結構:

• Flyweight: 抽象享元類 ,享元對象(細顆粒度)的接口定義

• ConcreteFlyweight: 具體享元類,享元對象(細顆粒度)的具體實現

• UnsharedConcreteFlyweight: 非共享具體享元類 ,不使用享元模式時的實現,多次複用細顆粒度狀態

• FlyweightFactory: 享元工廠類,內部維護享元池,維護細顆粒度集合

享元模式是一個考慮系統性能的設計模式,通過使用享元模式可以節約內存空間,提高系統的性能

/**
 * 享元對象的接口定義
 */
public interface NetworkDevice {
    String getType();
}
public class Switch implements NetworkDevice{
    @Override
    public String getType() {
        return "Switch";
    }
}
public class Hub implements NetworkDevice {
    private String type="Hub";
    @Override
    public String getType() {
        return type;
    }
}
public class DeviceFactory {
    private static List<NetworkDevice> deviceList=new ArrayList<>();

    public static NetworkDevice getNetworkDevice(String type){
        for(NetworkDevice networkDevice:deviceList){
            if(networkDevice.getType().equals(type)){
                return networkDevice;
            }
        }
        if(type.equals("Switch"))deviceList.add(new Switch());
        else deviceList.add(new Hub());
        return deviceList.get(deviceList.size()-1);
    }
}
public class FlyweightPattern {
    public static void main(String[] args){
        System.out.println(DeviceFactory.getNetworkDevice("Hub").getType());
        System.out.println(DeviceFactory.getNetworkDevice("Switch").getType());
    }
}
/*
Hub
Switch
*/

享元模式的優點在於它可以極大減少內存中對象的數量,使得相同對象或相似對象在內存中只保存一份。 享元模式的外部狀態相對獨立,而且不會影響其內部狀態,從而使得享元對象可以在不同的環境中被共享

享元模式使得系統更加複雜,需要分離出內部狀態和外部狀態,這使得程序的邏輯複雜化。

享元模式適用情況包括:一個系統有大量相同或者相似的對象,由於這類對象的大量使用,造成內存的大量耗費; 對象的大部分狀態都可以外部化,可以將這些外部狀態傳入對象中(也就是將大對象進行細粒度分解,使用對象時要按需注入數據);多次重複使用享元對象。

代理模式

在某些情況下,一個客戶不想或者不能直接引用一個對 象,此時可以通過一個稱之爲“代理”的第三者來實現間接引用。代理對象可以在客戶端和目標對象之間起到中介的作用,並且可以通過代理對象去掉客戶不能看到的內容和服務或者添加客戶需要的額外服務。

通過引入一個新的對象來實現對真實對象的操作或者將新的對象作爲真實對象的一個替身,這種實現機制即爲代理模式,通過引入代理對象來間接訪問一個對象,這就是代理模式的模式動機,即給某一個對象提供一個代理,並由代理對象控制對原對象的引用。

代理模式包含如下角色:

• Subject: 抽象主題角色,可以是抽象類也可以是接口,定義抽象功能

• Proxy: 代理主題角色

• RealSubject: 真實主題角色

靜態代理的一般模式爲

QSdseO.md.png

靜態代理就是通過構造一個代理類,內部維護一個代理對象,爲該對象的方法提供增強過後的功能,或根據需要設置功能的訪問權,靜態代理只能是一個具體的類有一個代理角色,功能不強。

public class TestDemo {
    interface IService{
        void say();
    }
    static class A implements IService{
        public void say(){
            System.out.println("I am A");
        }
    }
    static class Proxy implements IService{
        private A a;
        public Proxy(A a){
            this.a=a;
        }

        public void say(){
            System.out.println("我是代理,我先加點東西");
            a.say();
            System.out.println("我是代理,方法調用結束後加點東西");
        }
    }
     
    public static void main(String[] args){
        System.out.println("正常實現A");
        A a=new A();
        a.say();
        System.out.println("代理強化A");
        Proxy aProxy=new Proxy(a);
        aProxy.say();
    }

}
/*
執行結果爲:
正常實現A
I am A
代理強化A
我是代理,我先加點東西
I am A
我是代理,方法調用結束後加點東西
*/

代理模式能夠協調調用者和被調用者,在一定程度上降低了系統的耦合度,保護代理可以控制對真實對象的使用權限,代理模式應用的主要類型有:

遠程(Remote)代理:爲一個位於不同的地址空間的對象提供一個本地 的代理對象,這個不同的地址空間可以是在同一臺主機中,也可是在 另一臺主機中,遠程代理又叫做大使(Ambassador)。

• 虛擬(Virtual)代理:如果需要創建一個資源消耗較大的對象,先創建一 個消耗相對較小的對象來表示,真實對象只在需要時纔會被真正創建。

• Copy-on-Write代理:它是虛擬代理的一種,把複製(克隆)操作延遲 到只有在客戶端真正需要時才執行。一般來說,對象的深克隆是一個 開銷較大的操作,Copy-on-Write代理可以讓這個操作延遲,只有對象 被用到的時候才被克隆。
• 保護(Protect or Access)代理:控制對一個對象的訪問,可以給 不同的用戶提供不同級別的使用權限。

• 緩衝(Cache)代理:爲某一個目標操作的結果提供臨時的存儲空 間,以便多個客戶端可以共享這些結果。

• 防火牆(Firewall)代理:保護目標不讓惡意用戶接近。

• 同步化(Synchronization)代理:使幾個用戶能夠同時使用一個對 象而沒有衝突。

• 智能引用(Smart Reference)代理:當一個對象被引用時,提供 一些額外的操作,如將此對象被調用的次數記錄下來等。

動態代理:

    說實話,靜態代理的功能一點也不強,如果A,B,C...有許多類都需要在方法前加一點東西,不可能爲每一個類都寫一個對應的代理進行強化,如果能動態生成就好了。有需求必然有變化,java爲應對需求推出了類java.lang.reflect.Proxy同時對動態代理設置了一定的規範。

      首先,將需要切入的方法抽取出來放在接口中,A照樣實現接口從而實現方法。

      然後,寫一個通用代理類,代理類Proxy內部不在維護A,而是維護一個Object,該代理類要實現通用的代理接口InvocationHandler,該接口只有一個方法invoke()。Proxy內部維護Object,這個Object就可以代表任何上述接口,想要執行接口方法JVM就會自動調用內部invoke()方法。

invoke有三個參數:Object proxy,JVM自動生成的對應接口對象,一般不用管它、Method method:要切入的方法、Object args:切入的方法的參數

invoke()返回一個Object,在invoke()內部要使用method.invoke(obj,args)調用內部維護的Object的原始方法,然後返回

    最後想用代理時創建代理即可,要創建代理,簡單,調用(XXX)Proxy.newProxyInstance()即可,直接創建代理並進行強制類型轉換

該方法也有三個參數:ClassLoader loader:任意上述接口對象的類加載器、Class<?>[] interfaces:任意上述接口對象的數組、InvocationHandler h:代理

    簡而言之,動態代理就是在運行時動態生成指定接口的代理用於強化接口方法,就是動態生成靜態代理,在內部使用時,每次通過Proxy.newProxyInstance()指定接口與通用代理類,通用代理類的構造器傳入具體的接口實現類作爲參數。JVM內部自動生成一個與指定接口綁定的代理類,名爲ProxyX(X是自增數字),該代理類被傳入通用代理類的invoke方法中,同時將綁定到的實現接口的具體類的方法method與方法參數args一併傳入invoke,然後執行invoke()中的代碼,要調用原方法,須使用method.invoke(obj,args),返回一個Object作爲結果,返回該結果即可
public class TestDemo {
    interface IA{
        void sayA();
    }
    interface IB{
        void sayB();
    }
    static class A implements IA{
        public void sayA(){
            System.out.println("I am A");
        }
    }
    static class B implements IB{
        public void sayB(){
            System.out.println("I am B");
        }
    }
    static class MyProxy implements InvocationHandler {
        private Object obj;
        public MyProxy(Object obj){
            this.obj=obj;
        }

        public Object invoke(Object proxy, Method method,Object[] args){
            System.out.println("我是自動創建的代理"+proxy.getClass().getName());
            System.out.println("我是代理,我需要處理方法"+method.getName());
     
            if(args!=null)System.out.println("我是代理,該方法有參數"+args.length+"個");
            try{
                Object result=method.invoke(obj,args);//執行原始object方法
                return result;
            }catch (Exception e){
                e.printStackTrace();
            }
            return null;
        }
    }
     
    public static void main(String[] args){
        IA a=(IA) Proxy.newProxyInstance(IA.class.getClassLoader(),new Class<?>[]{IA.class},new MyProxy(new A()));
        a.sayA();
        IB b=(IB)Proxy.newProxyInstance(IB.class.getClassLoader(),new Class<?>[]{IB.class},new MyProxy(new B()));
        b.sayB();
    }

}

結果爲:
我是自動創建的代理mapper.$Proxy0

我是代理,我需要處理方法sayA

I am A

我是自動創建的代理mapper.$Proxy1

我是代理,我需要處理方法sayB

I am B

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章