策略模式、觀察者模式、代理模式、裝飾模式 應用場景和實現

有個大神寫的很好:

參考:設計模式學習筆記(四:策略模式)

參考:設計模式學習筆記(二:觀察者模式)

參考:設計模式學習筆記-代理模式

參考:設計模式--裝飾者模式與代理模式(重要)

參考:設計模式——代理模式與裝飾模式的異同?(重要)

參考:設計模式之裝飾模式

參考:java模式—裝飾者模式

參考:修飾者模式(裝飾者模式,Decoration)

一、策略模式:
?(1)解決場景:
某個功能有多個方案可以實現,要達到某個目的,需要根據具體的實際情況,選擇合適的方法,
?(2)如何實現:
分為兩個層次
 (a) 環境類
 環境類負責接收用戶的請求,并根據實際情況把相應的請求委托給一組策略類中的一個;

 (b) 一組策略類
  一組封裝了具體的實現類的算法,并負責具體的計算過程

(3)關鍵類圖:

?

?首先定義策略類的接口:?

public interface GameStrategy {public void goldCoin();}

其次 實現一組策略類:

public class normalStrategy implements GameStrategy {   @Override                                           public void goldCoin() {                            //                                              System.out.println("普通玩家沒有折扣");                 }                                                   
}       public class advancedStrategy implements GameStrategy {@Overridepublic void goldCoin() {// TODO Auto-generated method stubSystem.out.println("高級會員9折優惠");}
}

環境類的實現:

public class Context {                                //持有一個Strategy的引用                                   private GameStrategy mGameStrategy;               // 構造函數                                           public Context(GameStrategy strategy) {           this.mGameStrategy = strategy;                }                                                 public void setStrategy(GameStrategy strategy) {  this.mGameStrategy = strategy;                }                                                 public void goldCoin() {                          this.mGameStrategy.goldCoin();                }                                                 
}        

最后根據不同的情況進行調用:

public class main {                                          public static void main(String[] args) {                 //普通玩家策略                                             Context context = new Context(new normalStrategy()); context.goldCoin();                                  //高級玩家策略                                             context.setStrategy(new advancedStrategy());         context.goldCoin();                                 }                                                        
}   

?二、觀察者模式

(1)解決場景:
  (a) 對一個對象狀態的更新,需要其他對象同步更新
  (b) 對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節
觀察者模式,又稱為發布訂閱模式,它的特點:
  (a) subject 和 observer之間是松耦合的,各自獨立實現,
  (b) subject在發送廣播通知的時候,不需要指定具體的observer,observer可以自行決定是否要訂閱
  (c) 遵循常用設計原則:高內聚,低耦合
(2)如何實現:

關鍵類圖:

?定義觀察者接口:?

public interface Observer {void update(String message,String name);}

實現觀察者:

                                                                  
public class Bianyi1 implements Observer {                             //定義姓名                                                             private String bname = "張昊天";                                      @Override                                                          public void update(String message,String name) {                   System.out.println(bname+":"+name+"那里有新情況:"+ message);         }                                                                  
}                                                                     public class Bianyi2 implements Observer {                             //定義姓名                                                             private String bname = "石破天";                                      @Override                                                          public void update(String message,String name) {                   System.out.println(bname+":"+name+"那里有新情況:"+ message);         }                                                                  
}   

定義目標接口:

public interface Huairen {                  //添加便衣觀察者                               void addObserver(Observer observer);    //移除便衣觀察者                               void removeObserver(Observer observer); //通知觀察者                                 void notice(String message);            
} 

兩個實現目標的類:

import java.util.*;                                                          
/**                                                                          * 嫌犯大熊                                                                      */                                                                          
public class XianFan1 implements Huairen {                                   //別稱                                                                     private String name = "大熊";                                              //定義觀察者集合                                                                private List<Observer> observerList = new ArrayList<Observer>();         //增加觀察者                                                                  
    @Override                                                                public void addObserver(Observer observer) {                             if(!observerList.contains(observer)){                                observerList.add(observer);                                      }                                                                    }                                                                        //移除觀察者                                                                  
    @Override                                                                public void removeObserver(Observer observer) {                          if(observerList.contains(observer)){                                 observerList.remove(observer);                                   }                                                                    }                                                                        //通知觀察者                                                                  
    @Override                                                                public void notice(String message) {                                     for(Observer observer:observerList){                                 observer.update(message,name);                                   }                                                                    }                                                                        
}                                                                            import java.util.*;                                                          
/**                                                                          * 嫌犯黑狗                                                                      */                                                                          
public class XianFan2 implements Huairen {                                   //別稱                                                                     private String name = "黑狗";                                              //定義觀察者集合                                                                private List<Observer> observerList = new ArrayList<Observer>();         //增加觀察者                                                                  
    @Override                                                                public void addObserver(Observer observer) {                             if(!observerList.contains(observer)){                                observerList.add(observer);                                      }                                                                    }                                                                        //移除觀察者                                                                  
    @Override                                                                public void removeObserver(Observer observer) {                          if(observerList.contains(observer)){                                 observerList.remove(observer);                                   }                                                                    }                                                                        //通知觀察者                                                                  
    @Override                                                                public void notice(String message) {                                     for(Observer observer:observerList){                                 observer.update(message,name);                                   }                                                                    }                                                                        
}  

觀察者根據目標進行調用:

public class Clienter {                           public static void main(String[] args) {      //定義兩個嫌犯                                  Huairen xf1 = new XianFan1();             Huairen xf2 = new XianFan2();             //定義三個觀察便衣警察                              Observer o1 = new Bianyi1();              Observer o2 = new Bianyi2();          //為嫌犯增加觀察便衣                               
        xf1.addObserver(o1);                      xf1.addObserver(o2);                      xf2.addObserver(o1);                      xf2.addObserver(o3);                      //定義嫌犯1的情況                                String message1 = "又賣了一批貨";               String message2 = "老大要下來視察了";             xf1.notice(message1);                     xf2.notice(message2);                     }                                             
}       

?

三、代理模式:


(1)解決場景:
? ? (a) 當我們想要隱藏某個類時,可以為其提供代理類

  (b) 當一個類需要對不同的調用者提供不同的調用權限時,可以使用代理類來實現

  (c) 當我們要擴展某個類的某個功能時,可以使用代理模式,在代理類中進行簡單擴展
(2) 如何實現:
  (a) 代理類與委托類實現同一接口
  (b) 在委托類中實現功能,在代理類的方法中中引用委托類的同名方法
  (c) 外部類調用委托類某個方法時,直接以接口指向代理類的實例,這正是代理的意義所在:屏蔽。

(3) 類圖:

?(a) 抽象的主題:

public interface Moveable {void move()  throws Exception;
}

(b)真實主題:

public class Car implements Moveable {public void move() throws Exception {Thread.sleep(new Random().nextInt(1000));System.out.println("汽車行駛中…");}
}

(c) 事務處理器:

public class TimeHandler implements InvocationHandler {private Object target;public TimeHandler(Object target) {super();this.target = target;}/*** 參數:*proxy 被代理的對象*method 被代理對象的方法*args 方法的參數* 返回:*Object 方法返回值*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {long startTime = System.currentTimeMillis();System.out.println("汽車開始行駛…");method.invoke(target, args);long stopTime = System.currentTimeMillis();System.out.println("汽車結束行駛…汽車行駛時間:" + (stopTime - startTime) + "毫秒!");return null;}}

(d) 調用:

public class Test {public static void main(String[] args) throws Exception{Car car = new Car();InvocationHandler h = new TimeHandler(car);Class<?> cls = car.getClass();/***loader 類加載器*interfaces 實現接口*h InvocationHandler*/Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);m.move();}

?四、裝飾模式:

裝飾者(decorator)模式:在不改變對象自身的基礎上,在程序運行期間給對像動態的添加職責。與繼承相比,裝飾者是一種更輕便靈活的做法。
裝飾者模式的特點
可以動態的給某個對象添加額外的職責,而不會影響從這個類中派生的其它對象;

(1)應用場景:

(a)在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。

? (b)? 需要動態地給一個對象增加功能,這些功能也可以動態地被撤銷。? 當不能采用繼承的方式對系統進行擴充或者采用繼承不利于系統擴展和維護時。

(2)實現的例子:

最常見的就是輸入輸出流:

 BufferedReader in1 = new BufferedReader(new InputStreamReader(new FileInputStream(file)));//字符流DataInputStream in2 = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));//字節流// DataInputStream-從數據流讀取字節,并將它們裝換為正確的基本類型值或字符串// BufferedInputStream-可以通過減少讀寫次數來提高輸入和輸出的速度

?

從例子開始講解,比如今天你要出門約會,你肯定是要決定好你要穿什么樣的衣服出門,用衣服來裝飾下自己,讓自己擁有一個完美的約會。比如,你會穿一件襯衫,然后穿一件西服褲,最后穿皮鞋出門。這就是裝飾者模式的一個例子。為了實現這個功能,會有下面的代碼。
public class People {public void wearShirt(){System.out.println("******穿襯衫******");}
public void wearTrouser(){System.out.println("******穿西服褲******");}public void wearShoes(){System.out.println("******穿皮鞋******");}}

?

?
public class Client { 
public static void main(String[] args) {People people = new People();people.wearShirt();people.wearTrouser();people.wearShoes();} 
}

?

雖然上面的代碼實現了出門穿衣服的功能,但是這里會問題。如果我現在要增加一個功能,我要先穿襪子,再穿皮鞋。此時就要在People類中增加一個穿襪子的方法。這就違背了設計模式的開閉原則,所謂開閉原則就是類可以進行擴展,但是不可以進行修改。所以就有如下的設計:
public interface People {
public void wearClothing(); 
}
public class Xiaoming implements People{ 
private String name; 
public Xiaoming(){name = "小明";} 
public void wearClothing(){System.out.println(name+"******開始穿衣服******");}public String getName() {return name;}}
public abstract class Finery implements People { 
protected People people; 
public Finery(People people){this.people = people;}public abstract void wearClothing();}
public class ShirtFinery extends Finery {public ShirtFinery(People people){super(people);}@Overridepublic void wearClothing() {people.wearClothing();System.out.println("******穿襯衫******");} }
public class ShoesFinery extends Finery { 
public ShoesFinery(People people){super(people);}@Overridepublic void wearClothing() {people.wearClothing();System.out.println("******穿皮鞋*******");} 
}public class TrouserFinery extends Finery {public TrouserFinery(People people){super(people);}@Overridepublic void wearClothing() {people.wearClothing();System.out.println("******穿西服褲*******");} 
}
public class Client { public static void main(String[] args) {People people = new Xiaoming();Finery shirtFinery = new ShirtFinery(people);Finery trouserFinery = new TrouserFinery(shirtFinery);Finery shoesFinery = new ShoesFinery(trouserFinery);shoesFinery.wearClothing();}}

? (3)類圖:

People是定義了一個接口,用來添加具體的職責,而Xiaoming是具體的People,也就是被裝飾的對象。對于Finery實現了People接口,進而對People進行擴展,而Finery的子類就是具體的裝飾類,Finery中依賴People類,裝飾的具體對象。 這就是所謂的裝飾者模式。如果我要添加穿襪子的步驟,則只需要再添加一個實現類,完全不需要修改其他代碼(Client是客戶端類,肯定是要修改的)。

?

裝飾者模式和代理模式的區別:

兩種模式的特點


裝飾模式:

  在不改變接口的前提下,動態擴展對象的訪問。
  動態繼承,讓類具有在運行期改變行為的能力。
  裝飾模式,突出的是運行期增加行為,這和繼承是不同的,繼承是在編譯期增加行為。
  強調:增強,新增行為

代理模式:

  在不改變接口的前提下,控制對象的訪問。
  1.從封裝的角度講,是為了解決類與類之間相互調用而由此導致的耦合關系,可以說是接口的另外一個層引用。
    比如:在a類->b代理->c類這個關系中,c類的一切行為都隱藏在b中。即調用者不知道要訪問的內容與代理了什么對象。
  2.從復用的角度講,可以解決不同類調用一個復雜類時,僅僅因較小的改變而導致整個復雜類新建一個類。
    比如:a類->c類1;b類->c類2。
    可以變為a類->ca代理類->c類;b類->cb代理類-c類。
  代理模式,是類之間的封裝和(某方面的)復用。
  強調:限制,控制訪問

?

總結:

  1. 裝飾模式可以讓使用者直觀的看到增強了哪些功能,而代理模式完全限制了使用者。

  2. 對裝飾模式來說,裝飾者(Decorator)和被裝飾者(Cafe)都實現同一個 接口。

  3. 對代理模式來說,代理類(Proxy Class)和真實處理的類(Real Class)都實現同一個接口。

  4.?此外,不論我們使用哪一個模式,都可以很容易地在真實對象的方法前面或者后面加上自定義的方法。

裝飾模式與繼承的比較


  明顯的,裝飾模式可以動態的擴展對象的行為。

  比如某對象有30項行為,但是在第一階段用到1-20行為,第二階段用到11-30項行為,所以這時候,就可以只定義11-20的行為。

  在第一階段運行時,可以將1-10的行為以“裝飾1”給加上

  到第二階段運行時,可以將“裝飾1”去掉,將21-30的能以“裝飾2”給加上。

  但是繼承是在編譯期增加行為。

裝飾模式的優缺點


優點:

  1. 裝飾模式可以提供比繼承更多地靈活性。
  2. 可以通過一種動態的方式來擴展一個對象的功能,在運行時選擇不同的裝飾器,從而實現不同的行為。
  3. 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合。可以使用多個具體裝飾類來裝飾同一對象,得到功能更為強大的對象。
  4. 具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構件類和具體裝飾類,在使用時再對其進行組合,原有代碼無須改變,符合“開閉原則”。

缺點:

  1. 會產生很多的小對象(具體裝飾類),增加了系統的復雜性。
  2. 這種比繼承更加靈活機動的特性,也同時意味著裝飾模式比繼承易于出錯,排錯也很困難,對于多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較為煩瑣。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450961.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450961.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450961.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DQL、DML、DDL、DCL的概念與區別

http://blog.csdn.net/tomatofly/article/details/5949070 SQL語言的分類 SQL語言共分為四大類&#xff1a;數據查詢語言DQL&#xff08;Data Query Language&#xff09;&#xff0c;數據操縱語言DML&#xff0c;數據定義語言DDL(Data Definition Language)&#xff0c;數據…

python學習總結

1.python環境搭建方便&#xff0c;只需要安裝python解釋器 2.python把任意數據類型賦值給變量&#xff0c;不用定義類型 3.Python的整數浮點數沒有大小限制&#xff0c;不用擔心超過數值范圍。比如java的 int&#xff0c;long 4.python自帶最常用的list列表和dicitonary字典&am…

李國杰院士:國內開源社區的崛起需要一個過程

[CSDN.NET 付江/文]日前&#xff0c;在第二屆“龍芯杯”中國開源軟件設計大賽啟動儀式上&#xff0c;CSDN記者專訪了中國工程院院士、第三世界科學院院士李國杰。李國杰院士就國產基礎軟件現狀、面臨的機遇和挑戰、開源環境以及生態系統建設等話題分享了自己的看法。 打造自主…

SuperMap iObject入門開發系列之五管線屬性查詢

本文是一位好友“托馬斯”授權給我來發表的&#xff0c;介紹都是他的研究成果&#xff0c;在此&#xff0c;非常感謝。 管線屬性查詢功能針對單一管線圖層進行特定的條件查詢&#xff0c;然后將查詢結果輸出為列表&#xff0c;并添加點位閃爍功能&#xff0c;例如查詢污水管線中…

三類基于貪心思想的區間覆蓋問題

一、區間完全覆蓋問題 問題描述&#xff1a;給定一個長度為m的區間&#xff0c;再給出n條線段的起點和終點&#xff08;注意這里是閉區間&#xff09;&#xff0c;求最少使用多少條線段可以將整個區間完全覆蓋。 樣例&#xff1a;一個長度為8的區間&#xff0c;可選的線段有[2,…

ubuntu 常用軟件和命令

永久修改屏幕的分辨率   sudo gedit .profile 將下面的四句話加入。.profile文件的最后   cvt 1280 768   xrandr --newmode "1280x768_60.00" 79.50 1280 1344 1472 1664 768 771 781 798 -hsync vsync   xrandr --addmode Virtual1 "1280x768_60.00&q…

Eclipse搭建Android開發環境(安裝ADT,Android4.4.2)

見&#xff1a;http://blog.csdn.net/zht666/article/details/29837777 使用Eclipse做Android開發&#xff0c;需要先在Eclipse上安裝ADT&#xff08;Android Development Tools&#xff09;插件。 1.安裝JDK 1.7 JDK官網http://www.oracle.com/technetwork/java/javase/downlo…

C語言 位操作簡析

位運算 前面介紹的各種運算都是以字節作為最基本位進行的。 但在很多系統程序中常要求在位(bit)一級進行運算或處理。&#xff23;語言提供了位運算的功能&#xff0c; 這使得&#xff23;語言也能像匯編語言一樣用來編寫系統程序。 一、位運算符&#xff23;語言提供了六種位運…

算法:輸入一個鏈表,輸出該鏈表中倒數第k個結點。

算法&#xff1a;輸入一個鏈表&#xff0c;輸出該鏈表中倒數第k個結點。《劍指offer》 思路加到注釋里面了&#xff1b; 1&#xff1a;兩個if判斷是否返回值為空&#xff0c;首個為空&#xff0c;沒有第k個值&#xff1b; 2&#xff1a;for循環找到倒數第k個值&#xff0c;返回…

Spring事務那些事兒

&#xff08;一&#xff09;事務的隔離級別 大家都知道事務有四個屬性&#xff0c;即ACID&#xff08;原子性、一致性、隔離性、持久性&#xff09;。這四個里面稍微難理解點的是一致性和持久性。所謂的一致性是指&#xff1a;事務執行前后數據的一致性狀態&#xff0c;例如事…

Silverlight Blend動畫設計系列八:拖放(Drag-Drop)操作與拖放行為(DragBehavior)

Silverlight & Blend動畫設計系列八&#xff1a;拖放(Drag-Drop)操作與拖放行為(DragBehavior) 原文:Silverlight & Blend動畫設計系列八&#xff1a;拖放(Drag-Drop)操作與拖放行為(DragBehavior)在Silverlight中自身并沒有提供拖放功能的相關實現&#xff0c;要實現拖…

mysql查詢顯示行號

見&#xff1a;http://blog.csdn.net/muzizhuben/article/details/49449853 使用mysql查詢顯示行號&#xff0c;沒有像oracle這么方便。 不過也可以通過設定變量顯示行號&#xff0c;例如&#xff1a; -- 生成 行號 select r:r1 as rowno , a.* from my_tb a ,(select r:0) b …

scanf 用法大全

關于標準庫函數scanf論壇上很多人對scanf的不太了解&#xff0c;導致程序出錯&#xff0c;我想把scanf的具體用法貼出來&#xff0c;希望大家可以共同進步&#xff0c;有什么不對的地方可以提出來。int scanf(char *format&#xff0c;...);這應該是scanf的標準形式。先說說關于…

深入了解Spring IoC

IoC全稱Inversion of Control即控制反轉&#xff0c;它還有一個別名依賴注入。spring利用Ioc容器幫我們自動構建對象及注入依賴對象&#xff0c;減少了對象構建與業務代碼的耦合&#xff0c;使得我們能夠更加高效愉快的寫bug&#x1f41e;了(&#xffe3;▽&#xffe3;)"…

軟文營銷實戰記錄

最近拜讀了徐茂權老師的《 網絡營銷決勝武器(第2版)》&#xff0c;下面會梳理書中的內容&#xff0c;記錄下以后可能會用到的軟文營銷的技巧。 一、軟文載體 1、平面媒體軟文&#xff1a;報紙、期刊。 2、非正式出版的基于印刷、打印形式載體的軟文&#xff1a;企業印刷的宣傳冊…

oracle中rownum和row_number()的區別

見&#xff1a;http://www.jb51.net/article/65960.htm row_number()over(partition by col1 order by col2)表示根據col1分組&#xff0c;在分組內部根據col2排序&#xff0c;而此函數計算的值就表示每組內部排序后的順序編號&#xff08;組內連續的唯一的&#xff09;。 與ro…

java類加載順序

在java中類的加載、初始化都是在程序運行期完成的&#xff0c;雖然會稍微增加開銷&#xff0c;但是卻很大的增加了靈活性&#xff0c;我們可用在運行期間動態的去網絡或其他地方加載一個二進制流來作為程序代碼的一部分。接下來我們簡單介紹下java類加載過程。 從上圖中我們可…

dealloc不調用的情況

2019獨角獸企業重金招聘Python工程師標準>>> 1、沒有停止定時器 - (void)dealloc { [_timer invalidate]; _timer nil; } 2、VC中有代理Delegate&#xff0c;需要設置delegate的時候&#xff0c;設置為weak property (nonatomic,weak) id<ZoeEatDe…

day10-列表生成式

列表生成式即List Comprehensions&#xff0c;是Python內置的非常簡單卻強大的可以用來創建list的生成式。 1、生成一個列表 a [i for i in range(1,100) if i%21]print(list(a))或print(a)[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, …

jrebel、JavaRebel

見&#xff1a;https://baike.baidu.com/item/jrebel/1115725?fraladdin JRebel是一套JavaEE開發工具。中文名jrebel屬 性JavaEE開發工具資 費收費軟件作 用Jrebel 可快速實現熱部署JRebel是一套JavaEE開發工具。JRebel允許開發團隊在有限的時間內完成更多的任務修正…