1. 程式人生 > 實用技巧 >2020最新馬士兵Java架構師vip課程百度雲---代理模式與裝飾器模式的區別

2020最新馬士兵Java架構師vip課程百度雲---代理模式與裝飾器模式的區別

代理模式和裝飾器模式非常相近,本文通過舉例,針對倆者的區別進行探討。

示例:孩子會吃飯

public interface IChild {

    void eat();
}
建立孩子類,實現吃飯介面:

public class Child implements IChild{

    @Override
    public void eat() {

        Log.e("TAG","孩子吃飯");
    }
}

如果孩子太小,不會做飯,連吃飯都需要引導,這時候就需要一個代理幫助孩子正確處理吃飯流程:

建立父母(代理)類:

public class Parent implements IChild{

    private Child child;

    private Parent(Child child){

        this.child = child;
    }

    @Override
    public void eat() {

        Log.e("TAG","父母做飯");
        child.eat();
        Log.e("TAG","父母收拾餐具");
    }
}

其中有些孩子長大了,學會了自己做飯、自己吃飯,生活獨立自主:

建立孩子擴充套件(裝飾)類:

public class ChildWrapper implements IChild{

    private Child child;

    public ChildWrapper(Child child){

        this.child = child;
    }

    @Override
    public void eat() {

        Log.e("TAG","孩子做飯");
        child.eat();
        Log.e("TAG","孩子收拾餐具");
    }
}

以上是代理和裝飾的簡化寫法,如果不探究其表達的意義,倆者是沒有區別的。

但是從實際意義出發,就可以看出倆者的區別:

代理,偏重因自己無法完成或自己無需關心,需要他人干涉事件流程,更多的是對物件的控制。
裝飾,偏重對原物件功能的擴充套件,擴充套件後的物件仍是是物件本身。

這樣說有些抽象,繼續接著上例:

孩子長大了,需要去上學讀書,新增學生介面:

public interface IStudent {

    void readBook();
}

孩子多了一重身份--學生,故要實現學生介面:

public class Child implements IChild, IStudent {

    @Override
    public void eat() {

        Log.e("TAG", "孩子吃飯");
    }


    @Override
    public void readBook() {

        Log.e("TAG", "孩子讀書");
    }
}

此時,上述部分獨立自主的孩子(裝飾類),因為身份的增加,也要相應的擴充套件:

public class ChildWrapper implements IChild, IStudent {

    private Child child;

    public ChildWrapper(Child child) {

        this.child = child;
    }

    @Override
    public void eat() {

        Log.e("TAG", "孩子做飯");
        child.eat();
        Log.e("TAG", "孩子收拾餐具");
    }

    @Override
    public void readBook() {

        child.readBook();
    }
}

孩子成為了學生,但讀書不是宅家裡自學這麼簡單,需要有人教學,這顯然不是父母的任務,而是學校的事情。於是新增學校代理:

public class School implements IStudent {

    private ArrayList<IStudent> students;

    public void addStudent(IStudent student) {

        students.add(student);
    }

    @Override
    public void readBook() {

        for (IStudent student : students) {
            
            student.readBook();
        }
    }
}

學校招收學生入學,獨立自主的孩子作為裝飾類,本質還是孩子,肩負學生這一身份,可以作為學生入學,而原先的父母作為代理類不能入學:

Child child = new Child();
ChildWrapper wrapper = new ChildWrapper(child);
Parent parent = new Parent(child);

School school = new School();
school.addStudent(wrapper);

通過上述例子,相信可以直觀的看出:

孩子有吃飯和學習倆件任務,父母作為代理類之一,只能指導吃飯;學校作為代理類之一,只能指導學習。
對於某些獨立自主的孩子(裝飾類),它可能學習更加主動,吃完飯會主動收拾碗筷,但這些本來就是它原有功能的加強,它的本質仍然是孩子,依然可以享受父母、學校的代理幫助。

所以:
代理模式,注重對物件某一功能的流程把控和輔助。它可以控制物件做某些事,重心是為了借用物件的功能完成某一流程,而非物件功能如何。
裝飾模式,注重對物件功能的擴充套件,它不關心外界如何呼叫,只注重對物件功能的加強,裝飾後還是物件本身。

對於代理類,如何呼叫物件的某一功能是思考重點,而不需要兼顧物件的所有功能;
對於裝飾類,如何擴充套件物件的某一功能是思考重點,同時也需要兼顧物件的其它功能,因為再怎麼裝飾,本質也是物件本身,要擔負起物件應有的職責。

從上述例子也可以看出:
被裝飾者一旦身份增加,作為裝飾類,也需要相應的擴充套件,這必然造成編碼的負擔。

設計模式本身是為了提升程式碼的可擴充套件性,靈活運用即可,不必生搬硬套,非要分出個所以然來,裝飾器模式和代理模式的區別即是如此。

參考連結:http://www.cr7mufc520.cn/archives/mashibing11