設(shè)計模式:(三)結(jié)構(gòu)性模式

結(jié)構(gòu)性模式.png

一蛙卤、適配器模式

適配器模式.png

下面來看看適配器的三個角色:

  • Tagret目標角色:
    該角色定義把其他類轉(zhuǎn)換為何種接口拂蝎,也就是我們所期望接口可缚。
  • Adaptee源角色:
    你想把誰轉(zhuǎn)換成目標角色霎迫,它使已經(jīng)存在的、運行良好的類或?qū)ο蟪强矗?jīng)過適配器角色包裝女气,成為一個嶄新的角色。
  • Adapter適配器模式:
    適配器模式的核心角色测柠,其他兩個角色都是已經(jīng)存在的角色炼鞠,而適配器角色是需要新建立的,它的職責(zé)非常簡單:把源角色轉(zhuǎn)換為目標角色轰胁。

通用代碼實現(xiàn)

目標角色

public interface Target {
    //目標角色自有的方法
    public void request();
}
public class ConcreteTarget implements Target {
    public void request (){
    
    }
}

目標角色是一個已經(jīng)正式運行的角色谒主,不可能去修改角色中的方法。

源角色

public class Adaptee {
    //原有的業(yè)務(wù)邏輯
    public void doSomething(){
    
    }
}

適配器角色

public class Adapter extends Adaptee implements Target {
    public void reqest(){
        super.doSmothing();
    }
} 

二赃阀、橋接模式

橋接模式.png

橋接模式將繼承模式轉(zhuǎn)化成關(guān)聯(lián)關(guān)系霎肯,他降低了類與類之間的耦合度,減少了系統(tǒng)中類的數(shù)量榛斯,也減少了代碼量观游。

橋接是一個接口,它與一方應(yīng)該是綁定的驮俗,也就是解耦的雙方中的一方必然是繼承這個接口的懂缕,這一方就是實現(xiàn)方,而另一方正是要與這一方解耦的抽象方王凑,如果不采用橋接模式搪柑,一般我們的處理方式是直接使用繼承來實現(xiàn),這樣雙方之間處于強鏈接索烹,類之間關(guān)聯(lián)性極強工碾,如要進行擴展,必然導(dǎo)致類結(jié)構(gòu)急劇膨脹百姓。

uml.png

三渊额、組合模式

組合模式.png

組合模式,就是在一個對象中包含其他對象瓣戚,這些被包含的對象可能是終點對象(不再包含別的對象)端圈,也有可能是非終點對象(其內(nèi)部還包含其他對象,或叫組對象)子库,我們將對象稱為節(jié)點舱权,即一個根節(jié)點包含許多子節(jié)點,這些子節(jié)點有的不再包含子節(jié)點仑嗅,而有的仍然包含子節(jié)點宴倍,以此類推


組合模式類圖
  • Component抽象構(gòu)件角色
    定義參加組合對象的共有方法和屬性张症,可以定義一些默認的行為或?qū)傩浴?/p>

  • Leaf葉子構(gòu)件
    葉子對象,其下再也沒有其他的分支鸵贬,也就是遍歷的最小單位俗他。

  • Composite樹枝構(gòu)件
    樹枝對象,它的作用是組合樹枝節(jié)點和葉子節(jié)點形成一個樹形結(jié)構(gòu)阔逼。

public abstract class Component {
     //個體和整體都具有的共享
    public void doSomething(){
             //編寫業(yè)務(wù)邏輯
     }
}
/**
  *樹枝構(gòu)件
  */
public class Composite extends Component {
     //構(gòu)件容器
     private ArrayList<Component> componentArrayList = new ArrayList<Component>();
     //增加一個葉子構(gòu)件或樹枝構(gòu)件
     public void add(Component component){
             this.componentArrayList.add(component);
     }
     //刪除一個葉子構(gòu)件或樹枝構(gòu)件
     public void remove(Component component){
             this.componentArrayList.remove(component);
     }
     //獲得分支下的所有葉子構(gòu)件和樹枝構(gòu)件
     public ArrayList<Component> getChildren(){
             return this.componentArrayList;
     }
}
//樹葉節(jié)點是沒有子下級對象的對象兆衅,定義參加組合的原始對象行為,其通用源代碼
public class Leaf extends Component {
     /*
      * 可以覆寫父類方法
      * public void doSomething(){
      * 
      * }
      */
}

四嗜浮、裝飾器模式

裝飾器模式.png

裝飾模式通用類圖如下所示:


2018-11-13 下午5.12.56.png

在類圖中羡亩,有四個角色需要說明:

  • Component抽象構(gòu)件
    Component是一個接口或者是抽象類,就是定義我們最核心的對象危融,也就是最原始的對象畏铆。

  • ConcreteComponent 具體構(gòu)件
    ConcreteComponent是最核心、最原始吉殃、最基本的接口或抽象類的實現(xiàn)辞居,你要裝飾的就是它。

  • Decorator裝飾角色
    一般是一個抽象類蛋勺,做什么用呢瓦灶?實現(xiàn)接口或者抽象方法,它里面可不一定有抽象的方法抱完,在它的屬性里必然有一個private變量指向Component抽象構(gòu)件倚搬。

  • 具體裝飾角色
    ConcreteDecoratorA和ConcreteDecoratorB是兩個具體的裝飾類,你要把你最核心的乾蛤、最原始的、最基本的東西裝飾成其他東西

//抽象構(gòu)件
public abstract class Component {
     //抽象的方法
     public abstract void operate();
}

//具體構(gòu)件
public class ConcreteComponent extends Component {
     //具體實現(xiàn)
     @Override
     public void operate() {
             System.out.println("do Something");
     }
}

//抽象裝飾者
public abstract class Decorator extends Component {
     private Component component = null;        
     //通過構(gòu)造函數(shù)傳遞被修飾者
     public Decorator(Component _component){
             this.component = _component;
     }
     //委托給被修飾者執(zhí)行
     @Override
     public void operate() {
             this.component.operate();
     }
}
//具體的裝飾類
public class ConcreteDecorator1 extends Decorator {
     //定義被修飾者
     public ConcreteDecorator1(Component _component){
             super(_component);
     }
     //定義自己的修飾方法
     private void method1(){
             System.out.println("method1 修飾");
     }
     //重寫父類的Operation方法
     public void operate(){
             this.method1();
             super.operate();
     }
}
public class ConcreteDecorator2 extends Decorator {
     //定義被修飾者
     public ConcreteDecorator2(Component _component){
             super(_component);
     }
     //定義自己的修飾方法
     private void method1(){
             System.out.println("method1 修飾");
     }
     //重寫父類的Operation方法
     public void operate(){
             this.method1();
             super.operate();
     }
}

五捅僵、外觀模式

外觀模式.png

也就是提供一個訪問子系統(tǒng)的接口家卖,除了這個接口不允許有任何訪問子系統(tǒng)的行為發(fā)生,其通用類圖如下:


外觀模式類圖.jpeg
  • Facade門面角色
    客戶端可以調(diào)用這個角色的方法庙楚。此角色知曉子系統(tǒng)的所有功能和責(zé)任上荡。一般情況下,本角色會將所有從客戶端發(fā)來的請求委派到相應(yīng)的子系統(tǒng)去馒闷,也就說該角色沒有實際的業(yè)務(wù)邏輯酪捡,只是一個委托類。

  • subsystem子系統(tǒng)角色
    可以同時有一個或者多個子系統(tǒng)纳账。每一個子系統(tǒng)都不是一個單獨的類逛薇,而是一個類的集合。子系統(tǒng)并不知道門面的存在疏虫。對于子系統(tǒng)而言永罚,門面僅僅是另外一個客戶端而已啤呼。

// 子系統(tǒng)
public class ClassA {
     public void doSomethingA(){
             //業(yè)務(wù)邏輯
     }
}
public class ClassB {
     
     public void doSomethingB(){
             //業(yè)務(wù)邏輯
     }
}
public class ClassC {
     
     public void doSomethingC(){
             //業(yè)務(wù)邏輯
     }
}

//門面對象
public class Facade {
     //被委托的對象
     private ClassA a = new ClassA();
     private ClassB b = new ClassB();
     private ClassC c = new ClassC();
     //提供給外部訪問的方法
     public void methodA(){
         this.a.doSomethingA();
     }
     
     public void methodB(){
         this.b.doSomethingB();
     }
     
     public void methodC(){
         this.c.doSomethingC();
     }
}

六、享元模式

享元模式.png

要求細粒度對象呢袱,那么不可避免地使得對象數(shù)量多且性質(zhì)相近官扣,那我們就將這些對象的信息分為兩個部分:內(nèi)部狀態(tài)(intrinsic)與外部狀態(tài)(extrinsic)。
● 內(nèi)部狀態(tài)
內(nèi)部狀態(tài)是對象可共享出來的信息羞福,存儲在享元對象內(nèi)部并且不會隨環(huán)境改變而改變惕蹄,如id、name等治专,它們可以作為一個對象的動態(tài)附加信息卖陵,不必直接儲存在具體某個對象中,屬于可以共享的部分看靠。

● 外部狀態(tài)
外部狀態(tài)是對象得以依賴的一個標記赶促,是隨環(huán)境改變而改變的、不可以共享的狀態(tài)


享元模式類圖.jpeg
  • Flyweight——抽象享元角色
    它簡單地說就是一個產(chǎn)品的抽象類挟炬,同時定義出對象的外部狀態(tài)和內(nèi)部狀態(tài)的接口或?qū)崿F(xiàn)鸥滨。

  • ConcreteFlyweight——具體享元角色
    具體的一個產(chǎn)品類,實現(xiàn)抽象角色定義的業(yè)務(wù)谤祖。該角色中需要注意的是內(nèi)部狀態(tài)處理應(yīng)該與環(huán)境無關(guān)婿滓,不應(yīng)該出現(xiàn)一個操作改變了內(nèi)部狀態(tài),同時修改了外部狀態(tài)粥喜,這是絕對不允許的凸主。

  • unsharedConcreteFlyweight——不可共享的享元角色
    不存在外部狀態(tài)或者安全要求(如線程安全)不能夠使用共享技術(shù)的對象,該對象一般不會出現(xiàn)在享元工廠中额湘。

  • FlyweightFactory——享元工廠
    職責(zé)非常簡單卿吐,就是構(gòu)造一個池容器,同時提供從池中獲得對象的方法锋华。

//抽象享元角色
public abstract class Flyweight {
     //內(nèi)部狀態(tài)
     private String intrinsic;
     //外部狀態(tài)
     protected final String Extrinsic;
     //要求享元角色必須接受外部狀態(tài)
     public Flyweight(String _Extrinsic){
             this.Extrinsic = _Extrinsic;
     }
     //定義業(yè)務(wù)操作
     public abstract void operate();
     //內(nèi)部狀態(tài)的getter/setter
     public String getIntrinsic() {
             return intrinsic;
     }
     public void setIntrinsic(String intrinsic) {
             this.intrinsic = intrinsic;
     }
}

//具體享元角色嗡官。實現(xiàn)自己的業(yè)務(wù)邏輯,然后接收外部狀態(tài)毯焕,以便內(nèi)部業(yè)務(wù)邏輯對外部狀態(tài)的依賴衍腥。
//注意,我們在抽象享元中對外部狀態(tài)加上了final關(guān)鍵字纳猫,
//防止意外產(chǎn)生婆咸,什么意外?獲得了一個外部狀態(tài)芜辕,然后無意修改了一下尚骄,池就混亂了
public class ConcreteFlyweight1 extends Flyweight{
     //接受外部狀態(tài)
     public ConcreteFlyweight1(String _Extrinsic){
             super(_Extrinsic);
     }
     //根據(jù)外部狀態(tài)進行邏輯處理
     public void operate(){
             //業(yè)務(wù)邏輯
     }
}
public class ConcreteFlyweight2 extends Flyweight{
     //接受外部狀態(tài)
     public ConcreteFlyweight2(String _Extrinsic){
             super(_Extrinsic);
     }
     //根據(jù)外部狀態(tài)進行邏輯處理
     public void operate(){
             //業(yè)務(wù)邏輯
     }
}

//享元工廠
public class FlyweightFactory {
     //定義一個池容器
     private static  HashMap<String,Flyweight> pool= new HashMap<String,Flyweight>();
     //享元工廠
     public static Flyweight getFlyweight(String Extrinsic){
             //需要返回的對象
             Flyweight flyweight = null;
             //在池中沒有該對象
             if(pool.containsKey(Extrinsic)){
                     flyweight = pool.get(Extrinsic);
             }else{
                     //根據(jù)外部狀態(tài)創(chuàng)建享元對象
                     flyweight = new ConcreteFlyweight1(Extrinsic);
                     //放置到池中
                     pool.put(Extrinsic, flyweight);
             }
             return flyweight;
     }
}

七、代理模式

代理模式.png

代理模式通用類圖:


代理模式類圖.jpeg
  • Subject抽象主題角色
    抽象主題類可以是抽象類也可以是接口物遇,是一個最普通的業(yè)務(wù)類型定義乖仇,無特殊要求憾儒。

  • RealSubject具體主題角色
    也叫做被委托角色、被代理角色乃沙。它才是冤大頭起趾,是業(yè)務(wù)邏輯的具體執(zhí)行者。

  • Proxy代理主題角色
    也叫做委托類警儒、代理類训裆。它負責(zé)對真實角色的應(yīng)用,把所有抽象主題類定義的方法限制委托給真實主題角色實現(xiàn)蜀铲,并且在真實主題角色處理完畢前后做預(yù)處理和善后處理工作边琉。

//抽象主題類
public interface Subject {
     //定義一個方法
     public void request();
}

//真實主題類
public class RealSubject implements Subject {
     //實現(xiàn)方法
     public void request() {
             //業(yè)務(wù)邏輯處理
     }
}

//代理類
public class Proxy implements Subject {
     //要代理哪個實現(xiàn)類
     private Subject subject = null;    
     //默認被代理者
     public Proxy(){
             this.subject = new Proxy();
     }
     //通過構(gòu)造函數(shù)傳遞代理者
     public Proxy(Object...objects ){
     }
     //實現(xiàn)接口中定義的方法
     public void request() {
             this.before();
             this.subject.request();
             this.after();
     }
     //預(yù)處理
     private void before(){
             //do something
     }
     //善后處理
     private void after(){
             //do something
     }
}

JDK 自帶的動態(tài)代理:
java.lang.reflect.Proxy:生成動態(tài)代理類和對象;
java.lang.reflect.InvocationHandler(處理器接口):可以通過invoke方法實現(xiàn)
對真實角色的代理訪問记劝。
每次通過 Proxy 生成的代理類對象都要指定對應(yīng)的處理器對象变姨。

  1. 接口:Subject.java
public interface Subject {
    public String speak();
}
  1. 真實對象:RealSubject.java
public class RealSubject implements Subject{
  
    @Override
    public String speak() {
        System.out.println("speak");
        return "speak";
    }
}
  1. 處理器對象:MyInvocationHandler.java
public class MyInvocationHandler implements InvocationHandler {
    /**
     * 因為需要處理真實角色,所以要把真實角色傳進來
     */
    Subject realSubject ;

    public MyInvocationHandler(Subject realSubject) {
        this.realSubject = realSubject;
    }

    /**
     *
     * @param proxy    代理類
     * @param method    正在調(diào)用的方法
     * @param args      方法的參數(shù)
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("調(diào)用代理類");
        if(method.getName().equals("speak")){
             String str = (String)method.invoke(realSubject, args);
            System.out.println("調(diào)用的是說話的方法");
            return str ;
        }
    }
}
  1. 調(diào)用端:Main.java
public static void main(String[] args) {
        //真實對象
        Subject realSubject =  new RealSubject();

        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
        //代理對象
        Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), 
          new Class[]{Subject.class}, myInvocationHandler);

       
        proxyClass.speak();
    }

上一篇:設(shè)計模式:(二)創(chuàng)建型模式
下一篇:設(shè)計模式:(四)行為型模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厌丑,一起剝皮案震驚了整個濱河市定欧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怒竿,老刑警劉巖砍鸠,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異耕驰,居然都是意外死亡爷辱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門朦肘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饭弓,“玉大人,你說我怎么就攤上這事媒抠∈酒簦” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵领舰,是天一觀的道長。 經(jīng)常有香客問我迟螺,道長冲秽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任矩父,我火速辦了婚禮锉桑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘窍株。我一直安慰自己民轴,他們只是感情好攻柠,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著后裸,像睡著了一般瑰钮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上微驶,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天浪谴,我揣著相機與錄音,去河邊找鬼因苹。 笑死苟耻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扶檐。 我是一名探鬼主播凶杖,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼款筑!你這毒婦竟也來了智蝠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤醋虏,失蹤者是張志新(化名)和其女友劉穎寻咒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颈嚼,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡毛秘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了阻课。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叫挟。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖限煞,靈堂內(nèi)的尸體忽然破棺而出抹恳,到底是詐尸還是另有隱情,我是刑警寧澤署驻,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布奋献,位于F島的核電站,受9級特大地震影響旺上,放射性物質(zhì)發(fā)生泄漏瓶蚂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一宣吱、第九天 我趴在偏房一處隱蔽的房頂上張望窃这。 院中可真熱鬧,春花似錦征候、人聲如沸杭攻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兆解。三九已至馆铁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間痪宰,已是汗流浹背叼架。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留衣撬,地道東北人乖订。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像具练,于是被迫代替她去往敵國和親乍构。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容