首頁 > Java > java教程 > 主體

java常用設計模式

高洛峰
發布: 2016-12-12 13:32:52
原創
1186 人瀏覽過

java設計模式;
一個程式設計師對java設計模式的理解:
「不懂」為什麼要把很簡單的東西搞得那麼複雜。後來隨著軟體開發經驗的增加才開始明白我所看到的「複雜」恰恰就是設計模式的精髓所在,我所理解的「簡單」就是一把鑰匙開一把鎖的模式,目的僅僅是著眼於解決現在的問題,而設計模式的“複雜”就在於它是要構造一個“萬能鑰匙”,目的是提出一種對所有鎖的開鎖方案。在真正理解設計模式之前我一直在編寫“簡單”的程式碼.
這個“簡單”不是功能的簡單,而是設計的簡單。簡單的設計意味著缺少靈活性,程式碼很鋼硬,只在這個專案裡有用,拿到其它的專案中就是垃圾,我稱之為「一次性程式碼」。

-->要使程式碼可被重複使用,請用'設計模式'對你的程式碼進行設計.

很多我所認識的程式設計師在接觸到設計模式之後,都有一種相見恨晚的感覺,有人形容學習了設計模式之後感覺自己好像已經脫胎換骨,達到了新的境界,還有人甚至把是否了解設計模式作為程式設計師劃分水平的標準。

我們也不能陷入模式的陷阱,為了使用模式而去套模式,那樣會陷入形式主義。我們在使用模式的時候,一定要注意模式的意圖(intent),而不 要過多的去關注模式的實作細節,因為這些實作細節在特定情況下,可能會發生一些改變。不要頑固地認為設計模式一書中的類別圖或實作程式碼就代表了模式本身。


設計原則:(重要)
1.
邏輯程式碼獨立到單獨的方法中,注重封裝性--易讀,易復用。
不要在一個方法中,寫下上百行的邏輯程式碼。把各小邏輯程式碼獨立出來,寫於其它方法中,易讀其可重複呼叫。
2.
寫類,寫方法,寫功能時,應考慮其移植性,復用性:防止一次性代碼!
是否可以拿到其它同類事物中應該?是否可以拿到其它系統中應該?
3.
熟練運用繼承的思想:
找出應用中相同之處,且不容易發生變化的東西,把它們抽取到抽象類別中,讓子類別去繼承它們;
繼承的思想,也方便將自己的邏輯是建立在別人的成果之上。如ImageField extends JTextField;
熟練運用介面的想法:
找出應用程式中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。


把很簡單的東西搞得那麼複雜,一次性代碼,設計模式優勢的實例說明:(策略模式)
說明:
模擬鴨子遊戲的應用程序,要求:遊戲中會出現各種顏色外形的鴨子,一邊游泳戲水,一邊呱呱叫。

第一種方法:(一次性程式碼)
直接寫出各種鴨子的類別:MallardDuck//野鴨,RedheadDuck//紅頭鴨,各類有三種方法:
quack():叫的方法
swim( ):遊水的方法
display():外形的方法

第二種方法:運用繼承的特性,將其中共同的部分提升出來,避免重複編程。
即:設計一個鴨子的超類別(Superclass),並讓各種鴨子繼承這個超類別。
public class Duck{
     public void quack(){  //呱呱叫
             im(){   //游泳
            System.out.println(" 游泳") ;
      }    
     public  abstratact void display(); /*因為外觀不一樣,讓子類別自己去決定了。 */
}

對於它的子類別只需簡單的繼承就可以了,並實作自己的display()方法。

//野鴨

 public class MallardDuck extends Duck{
     public void display(){
         headDuck extends Duck {
     public void display(){
          System.out.println("紅頭鴨的顏色...");
   }
}

的是,現在又提出了。這個對於我們OO程式設計師,在簡單不過了,在超類別中加一

個方法就可以了。
public class Duck{
     public void quack(){  //呱呱叫
             im(){   //游泳
            System.out.println(" 游泳") ;
    }    
    public  abstract void display(); /*因為外觀不一樣,讓子類別自己去決定了。 */
   public void fly(){
        System.out.println("飛吧!鴨子"); 
  }
}
對於無法飛的鴨子,在子類別中只需簡單的覆蓋。
//殘廢鴨
 public class DisabledDuck extends Duck{
     public void display(){
          System.out.println("殘廢鴨的顏色...》    //覆蓋,變成什麼事都不做。 
  }

其它會飛的鴨子不用覆蓋。

這樣所有的繼承這個超類別的鴨子都會fly了。但問題又出來了,客戶又提出有的鴨子會飛,有的不能飛。

>>>>>>點評:
對於上面的設計,你可能發現一些弊端,如果超類有新的特性,子類都必須變動,這是我們開發最不喜歡看到的,一個類變讓另一個類別也跟著變,這有點不符合OO設計了。這樣很顯然的耦合了一起。利用繼承-->耦合度太高了.

第三種方法:

用介面改進.

我們把容易引起變化的部分提取出來並封裝之,來應付以後的變法。雖然程式碼量加大了,但可用性提高了,耦合度也降低了。

我們把Duck中的fly方法和quack提取出來。

    public interface Flyable{
       public interface Flyable{
      public void fly(); 

  }

   public interface Quackable{
       public void swim(){   //游泳
            System.out.println(" 游泳");
    }    
    public  abstract void display( 
    public  abstract void display(); */
}
 而MallardDuck,RedheadDuck,DisabledDuck 就可以寫成為:
//野鴨
 public class MallardDuck extends Duck  implements  println("野鴨的顏色. ..");
   }
   public void fly(){
    //實作此方法
  }
   public void quack(){
 Duck implements Flyable,Quackable{
     public void display(){
          System.out.println("紅頭鴨的色彩...");   public void quack(){
    //實作此方法
  }

//殘廢鴨只實現Quackable(能叫不能飛)
 public class Disable   System.out.println ("殘廢鴨的顏色...");
   }
   public void quack(){
    //實作此方法
  }
}

>>>>>>點評:
  }
}

>>>>>>點評:
  }
}

>>>>>點評的程序就降低了它們之間的耦合。
不足:
Flyable和 Quackable介面一開始似乎還挺不錯的,解決了問題(只有會飛到鴨子才實現 Flyable),但是Java介面不具有實作程式碼,所以實作介面無法達到程式碼的複用。

第四種方法:

對上面各方式的總結:
繼承的好處:讓共同部分,可以復用.避免重複編程.

繼承的不好:耦合性高.一旦超類添加一個新方法,子類別都繼承,擁有此方法,

                        

                         繼承時,子類別就不可繼承其它類別了.🎠              且可讓實現類別,繼承或實現其它類別或介面.

介面的不好:不能真正實現程式碼的複用.可用以下的策略模式來解決.

 

------------------------- strategy(策略模式) -------------------------

我們有一個設計原則:

找出應用上相同之處,且不容易改變的東西,把它們抽取到抽象類別中,讓子類別去繼承它們;

找出應用程式中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。 -->important.


現在,為了要分開“變化和不變化的部分”,我們準備建立兩組類(完全遠離Duck類),一個是"fly"相關的,另一個

是“quack”相關的,每一組類別將實現各自的動作。比方說,我們可能有一個類實現“呱呱叫”,另一個類實現“吱吱

叫”,還有一個類實現“安靜”。

先寫兩個介面。 FlyBehavior(飛行行為)與QuackBehavior(叫的行為).

  public interface FlyBehavior{

     public void fly();     

  我們在定義一些針對FlyBehavior的具體實現。

 public class FlyWithWings implements FlyBehavior{
    public void  fly(){
     //實現了所有有翅膀的鴨子飛行行為。
   }
 }

public class FlyNoWay implements FlyBehavior{
 
    public void  fly(){
  幾種具體實現。
public class Quack implements QuackBehavior{
    public void quack(){
      //實現呱呱叫的鴨子

  }

}
.
      //實現吱吱叫的鴨子 
}
}
 
public class MuteQuack implements QuackBehavior{
    public void quack(){
      //什麼都不做,不會叫
}被其他的物件重複使用,因為這些行為已經與鴨子類別無關了。而我們增加一些新

的行為,不會影響到既有的行為類,也不會影響「使用」到飛行行為的鴨子類。

最後我們來看看Duck 如何設計。
     public class Duck{        --------->在抽象類別,宣告各介面,定義各介面對應的方法.
      Fly   public Duck() {}
       public abstract void display();
       public void swim(){
      Fly(){
            flyBehavior.fly();  -->因為為介面,會依繼承類別實作的方式,而呼叫對應的方法.
     }
     public void performQuack(){
          ackBehavior.quack();();

看看MallardDuck如何實現。
----->透過構造方法,產生'飛','叫'具體實現類別的實例,從而指定'飛','叫'的特定屬性
 public class MallardDuck extends Duck{
       = new FlyWithWings ();
        quackBehavior = new Quack(); 
      //因為MallardDuck
   }
 }
 如此滿足了即可以飛,又可以叫,同時展現自己的顏色了。

這樣的設計我們可以看到是把flyBehavior ,quackBehavior 的實例化寫在子類別中了。我們也可以動態的來決定。
  我們只要在Duck中加上兩個方法。

 

在構造方法中對屬性進行賦值與用屬性的setter的區別:

構造方法中對屬性進行賦值:固定,不可變;

用屬性的setter,可以在實例化對象後,動態固定,不可變;

用屬性的setter,可以在實例化對象後,動態固定,不可變;

用屬性的setter,可以在實例化對象後,動態固定,不可變;

用屬性的setter,可以在實例化對象後,動態的變化,比較靈活。


 


  public class Duck{
      FlyBehavior flyBehavior;//介面
     ){
            this.flyBehavior = flyBehavior;
     }
    public void setQuackBehavior(QuackBehavior quackhavior this.quackBehavior= quackBehavior;
     }

 }



------------------------- static Factory Method(靜態工廠) ----- --------------------
(1)

在設計模式中,Factory Method也是比較簡單的一個,但應用非常廣泛,EJB,RMI,COM,CORBA ,Swing中都可以看到此模式

的影子,它是最重要的模式之一.在很多地方我們都會看到xxxFactory這樣命名的類.


(2)
基本概念:
FactoryMethod是一種創建性模式,它定義了一個創建對象的接口,但是卻讓子類來決定具體實例化哪一個類.

通常我們將Factory Method作為一種標準的創建對象的方法。一個類別無法預料要建立哪種類別的物件或是一個類別需要由子類別來指定建立的物件時我們就需要用到Factory Method 模


式了.

---------- ---------------------- singelton(單例模式) ---------------------- ----------

基本概念:

Singleton 是一種創建性模型,它用來確保只產生一個實例,並提供一個訪問它的全局訪問點.對一些類來說,保證只有一個實例是很重要的,例如有的時候,數據庫連接或Socket 連接要受到一定的限制,必須保持同一時間只能有一個連接的存在.

運用:

在於使用static變量;

創建類對象,一般是在建構方法中,或用一個方法來建立類別物件。都是讓類別的實例是唯一的。

但單態模式的實作方式是:

在類別的內部.即在建構方法中,或靜態的getInstace方法中,進行判斷,若實例存在,則直接傳回,不進行建立;

共享模式的實作方式是:

每次要用到此實例時,先去此hashtable中獲取,若獲取為空,則生成實例,且將類的實例放在一人hashtable中,若獲取不為空,則直接用此實例。

 

 

 

(2)

實例一:

public class Singleton {  

   null)

      s = new Singleton();

    return s;

  }

}

// 測試類別
class singletonTest {
  public static void main(String[] args) {
stance();
if (s1==s2)
      System.out.println("s1 is the same instance with s2");
    else
      System。

singletonTest運行結果是:
s1 is the same instance with s2

(3)
實例二:
class Singleton {
  static boolean instance_flag = false; // true if 1 instance
  public Singleton() {
 nce allowed");
else
      instance_flag = true; // set flag for 1 instance
  }
}

------------------------------- - 觀察者模式(Observer) --------------------------------

(1)
基本概念:
觀察者模式屬於行為型模式,其意圖是定義物件間的一種一對多的依賴關係,當一個物件的狀態改變時,所有依賴它的物件都會被通知並被自動更新。

這一個模式的關鍵物件是目標(Subject)和觀察者(Observer)。一個目標可以有任意數目的依賴它的觀察者,一旦目標的狀態改變,所有的觀察者都得到通知,作為對這個通知的回應,每個觀察者都將查詢目標以使其狀態與目標的狀態同步。

適用場景:

觀察者模式,用於存在一對多依賴關係的物件間,當被依賴者變化時,通知依賴者全部進行更新。因此,被依賴者,應該有新增/刪除依賴者的方法,並且可以將新增的依賴者放到一個容器中;且有一個方法可以通知依賴者進行更新。

(2)

思想:
(一)
建立目標(subject)與觀察者(observer)介面:
目標(subject)介面:
建立一個註冊觀察者物件的介面; public void attach(Observer o) ;
建立一個刪除觀察者物件的介面; public void detach(Observer o);
建立一個當目標狀態改變時,發布通知給觀察者物件的介面; public void notice();

觀察者(observer )介面:

建立一個當收到目標通知後的更新介面: public void update();

(3)

實例:
老師又電話號碼,學生需要知道老師的電話號碼以便於在合時的時候撥打,在這樣的組合中,老師就是一個被觀察者

(Subject),學生就是需要知道資訊的觀察者,當老師的電話號碼改變時,學生得到通知,並更新相應的電話記

錄。

具體實例如下:

Subject程式碼:
public interface Subject{
    public void attach(Observer o);
    public void detach(Observer o);
    public void detach(Observer o);
public interface Observer{
    public void update();

}


Teacher程式碼;
import java.util.Vector;
public class Teacher implements Subject{

  public Teacher(){

       phone = "";
       students = new Vector();
    }
    public  void attach(Observer o){
  Observer o){
       students.remove(o);
}
    public void notice(){
       for(int i=0;i         public void setPhone( String phone){
       this.phone = phone;
       notice();    --關鍵
      }
}

學生代號:
公課學生實現觀察者{
    private String name;
    private String phone;
   name;
       Teacher = t;
}
    public void show(){
       System.out.println("姓名:"+姓名+"n老師電話:"+電話);
    }Phgetp. ) ;
}
}
Client程式碼:
package Observer;
import java.util.Vector;
public class Client{         -->只目標者,觀察者,另一個的向量,只為了輸入結果。
    public static void main(String[] args){
       Vector Students = new Vector();
                 Student st = new Student("lili “+i,t);
學生add(st);
t.t.attach(st);
}
t.setphone(“ 888803807”);
for(&int i = 0; ilti< ++++e++++sepphone; i< i ++) ((Student)students.get(i)).show();
       t.setPhone("88808880");
    t.setPhone("88808880");
    ;i              ((Student)students.get(i) )).show();
   應用在文件和圖表程式的製作。


---- -------------------------- 迭代器模式(Iterator) ----------- ------- -------------
(1)
基本概念:
迭代器模式屬於行為型模式,其意義是提供一種方法順序來存取一個聚合物件中得到各個元素,榕不需要暴露該物件的

內部表示。

至少可以歷遍first,next,previous,last,isOver,或歷遍選擇符合某種條件的子元素。

(2)

結構:
由一個介面與一個實作類別組成。
介面:
主要是定義各個歷次的方法。
實作類別:

需要一個計算點private int current=0 ;以及一個ContainerVector,來存在原來的進行歷遍的一團東西;再對介面方法進


行實作.
Iterator介面:
套件迭代器;
公用介面迭代器{
/ *
Item:即集合中的各物件的類型。若為String,即把所有的ITEMString,若為其他自訂的類,則改為自訂各的類

的接口,或類。 --->重要。  

*/

    public Item first();

    public Item next();

    public boolean isDone();
);
package iterator;
import java.lang. util.Vector;
public class Controller 實作Iterator{
    private int current =0;
  = v;

    }

    public Item first(){
       current = 0;
return (Item)channel.get(current);
    }
    public Item  get(current);
    }
public Item currentItem(){

       return (Item) )channel.get(current);

    }
    public boolean isDone(){
>
}

Television介面:
package iterator;
import java.util.Vector;
public interface Television{
    public Iterator createIterator();
}
HaierTV類別實作了Television介面。
package iterator;
import java.util.Vector;
public class HaierTV implements Television{     ---對象
    private Vector chan
);       channel.addElement(new Item( "channel 1")); --各元素,用VECTOR存放
       channel.addElement(new Item("channel 2"));
       channel new Item("channel 4"));
       channel.addElement(new Item("channel 5"));
       channel.addElement(new Item("chan 6")); 7"));
    }
    public Iterator createIterator(){
       return new Controller(channel);    ient客戶端:
package iterator;
public class Client{
    public static void main(String[] args){
       Television tv = new HaierTV();
    st().getName( ));
       while(!it.isDone()){
           System.out.println(it.next().getName             
package iterator;
public類 Item{
    private String name;
    public Item(String aName){
       name = aName;
       }
}

---------- -------------------- 外觀模式(Facade) ------------------------- ------
(1)
外觀模式屬於結構型模式,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
外觀模式的主要用途就是為子系統的複雜處理過程提供方便的呼叫方法,使得子系統更容易被使用。
-->將複雜的過程包含在裡面,提供一個簡單的應用接口即可.

(2)
例如在一個泡茶的過程中,需要作如下的工作:燒開水,準備茶葉,把茶葉放在被子裡,把燒開的水放到茶杯中,只

有經過這些過程之後才能泡出好的茶葉來。這是一個常用的步驟,80%的泡茶步驟都是這個樣子的,可以把這些動作串

聯起來,形成一個整體的步驟.如下例的MakeACuppa(),使用了facade的模式,這樣在呼叫步方法時就比較方便。這便

是外觀模式,裡面的細節被屏蔽掉了。

public class TeaCup{.....}

public class TeaBag{.....}

public class Water{.....}

public class FacadeCuppaMaker{
  (){

       System.out.println("FacadeCuppaMaker 準備沖茶了");

    }

    public   TeaBag teaBag= new TeaBag();

       Water water = new Water();

       cup.addFacadeTeaBag(teaBag);

       water.boilFacadeWater(); ag();

       return cup;

    }

}

---- -------------------------- 適配器模式(adapter) ------------------- ------------

(1)

適配器模式的意圖是將一個已存在的類別/介面進行複用,將其轉換/具體化成客戶希望的另外的一個類別/介面。

(2)
如何實例復用:
將要進行複用的類,放到目標類的構造方法中,進行實例化,然後在目標類的相應方法中,進行調用,修改原來方法

中的參數,或加入對應的邏輯。即復用了已有類別的原來方法。

要重複使用的類別:
public class Adaptee{
    public long getPower(long base,long exp){
       long ult=1;      result*= base;
       return result;
    }
}

目標類別:--也可直接實現,不用介面。

public interface Target{

    public long get2Power(long exp);
}

public class Adapter implements Target{

    private Adapt ();

    }
    public long get2Power( long exp){
       return pt.getPower(2,exp);   ---修改原先方法中的參數,
    }
}

(3)
又如:已添加的方法在SCM :
public boolean updateRecordStates(Double recordId,Double tableNameMapping,int state,boolean

subRecordUpdate) throws RemoteException;
已有實作類別:
public boolean updateRecordStates(dateRecord rows RemoteException
{
return moveTable.updateRecordStates(recordId,tableNameMapping,state,subRecordUpdate); 

}


若採用適配器模式:
接口:

public boolean updateStatesAdapterSelf teException;

實現類別:
public boolean updateStatesAdapterForSelfPanel(Double recordId,Double tableNameMapping,int state)

throws RemoteException

{

 return this.updateRecordStates(Exception
{
 return this.updateRecordStates(freop); --------------------- 代理模式(Proxy) ------------------------ -------

(1)

代理的好處:
--->是可以在間接訪問對象的同時,要其前或後,添加其它的邏輯代碼.
--->對原來邏輯進行加入其它邏輯,最終產生新的邏輯.即:對類別的方法添加一些額外的邏輯,產生新的方法邏輯.

(2)
靜態代理: 
-->一個原類別與一個代理類別要一一對應。
-->兩者都實現共同的介面或繼承相同的抽象類別;

-->只是在代理類別中,實例化原類,在原類別方法的前後添加新的邏輯。

如下:
抽象角色:
abstract public class Subject
{
    abstract public void request();

}


真實角色:
public class RealSubject extquestSubject
真角色
       {
              系統.out. println("From real subject.");
       }
}

代理角色:
public class ProxySubject extends Subject

{5privpriat
       public ProxySubject()
{ realSubject=new RealSubject(); }

       public void request()  //與原始方法名稱相同
      .request();  //此處執行真實物件的request方法

postRequest();

      }


    private void preRequest()

    {

      ()
    {

        //something you want to do after requesting

    }
}

客戶端呼叫:
Subject sub=new ProxySubject();
Sub.request();

(3)

動態代理類別

Java動態代理類別位於Java.lang.reflect包下,一般主要涉及以下兩個類別:
1)

Interface InvocationHandler:此介面中僅定義了一個方法:invoke(Object obj,Method method, Object[] args)


。在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,args為該方法的參數數組。這個抽象方法

在代理類別中動態實作。
2)
Proxy:此類別即為動態代理類,其中主要包含以下內容:
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):傳回代理類別

的一個實例,傳回後的代理類別可以當作被代理類別使用。
所謂Dynamic Proxy是這樣一種class:它是在運行時產生的class,在產生它時你必須提供一組interface給它,然後

該class就宣稱它實現了這些 interface。
3)
在使用動態代理類別時,我們必須實作InvocationHandler接口,
public interface Subject
{
    public void request();
}

port角色.reflect.Method;

import java.lang.reflect.InvocationHandler;

public class DynamicSubject implements InvocationHandler {
  private Object sub;
  public DynamicSubject(Object private Object invoke(Object proxy , Method method, Object[] args) throws Throwable {
    System.out.println("before calling " + method);

    method.invoke(sub,args);

    method.invoke(sub,args); + method);

    return null;

  }

}

==>

method.invoke(sub,args);

其實就是呼叫被代理物件的將要執行的方法,方法參數,args為執行被代理物件對應操作所

需的參數。透過動態代理類,我們可以在呼叫之前或之後執行一些相關操作。

客戶端:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;

import java.

{

    static public void main(String[] args) throws Throwable

    {
      RealSubject rs = new Realisject(); (rs);  //初始化代理類別
Subject subject = (Subject) Proxy.newProxyInstance(rs.getClass().getClassLoader(),rs.getClass

().getInterfaces(),ds );

    二:

package dynamicProxy;
public interface Work {
 public void startWork();
}

package dynamicProxy;
public class JasonWork implements Workoid work...");

 }

}

public interface Play {

 public void startPlay();

}

public class JasonPlay implements Play { public void start to play...");
 }
}

public class Test {

public static void main(String[] args) 
{
                InvocationHandler dynamicProxy=new DynamicProxy(work) ;
                Work jasonproxy=(Work)Proxy.newProxyInstance(work.getClass().getClassLoader(),      jasonproxy.startWork();

  JasonPlay play=new JasonPlay();

  InvocationHandler dynamicProxy=new DynamicProxy(play);

  Play jasonproxy=(Play)Proxy.newProxyInstance(play.getClass().getClassLoader(),

playgetClass().Proynamic;

  jasonproxy.startPlay();

 }
}
===>動態代理類別,可以與任何類型的真實類別(work/play),進行結合,進行動態的代理.

 ----------------------------- 狀態模式(state) ---------------- ---------------

(1)

State模式定義:
不同的狀態,不同的行為; 或說,每個狀態有著相應的行為.
適用場合:
State模式在實際使用上比較多,適合"狀態的切換".因為我們經常會使用If elseif else 進行狀態切換, 如果針對狀態的這樣判斷切換反覆出現,我們就要聯想到是否可以採取State模式了.

-->適合於內部狀態,不斷循環變化的.

(2)
一個state,包括兩部分: 物件+ 物件內部的屬性(屬性介面+具體屬性)

一個物件,要有其屬性,以及其setter,getter.且設定好其初始狀態+一個呼叫顯示狀態的方法(裡面就是狀態呼叫自身的顯示方法).

一個屬性介面,應該有一個執行的方法.
一個具體屬性,須包含物件進去,實作方法中,須設定物件下一個要顯示的屬性-->從而在物件下次呼叫方法時,其屬性值會變化.

 

狀態模式與觀察者模式的區別:

狀態模式,也跟觀察者模式一樣,是一對多的模式。但觀察者模式是「一」變了,所有的「多」也會更新。

狀態模式,強調的是:「多」是「一」的各個狀態,「一」的各個狀態,進行不斷的循環。

 

如何建立一與多的關係:

“多”,都是實現一個介面的。所以,在「一」的類別中,聲明的是「多」的介面;若「多」中要建立與「一」的關係,只須直接在類別中聲明「一」即可。

 

 

(3)
代碼:
public interface Color {
 public void show();

}

package state; ) {

return color;

 }
 public void setColor(Color color) {
  this.color = color;
 }
 
 public Light()
{
  color.show();
 }
 
}

class RedColor implements Color
{
 Light light;
 public RedColor(Light light)
 Light light;
 public RedColor(Light light)
 Light oid show()
 {
 System.out.println("the color is red,the car must stop !");

 System.out.println("write down all logic shoud do this in this state.....");

..... light.setColor(new GreenColor(light));
 }
}

class GreenColor implements Color
{
 Light light;
 public GreenColor(Light light)
 Light light;
 public GreenColor(Light light)
 {🠎 ()
 {
 System.out.println("the color is green,the car can run !");
 System.out.println("write down all logic shoud do this in this state.....") ;
  light.setColor(new YellowColor(light));

 }

}

class YellowColor implements Color
{
 Light light;
 public void show()
 {
 System.out.println("the color is yellow,the car shoud stop !");
 System.out.println("write down all logic shoud do this in this do..... ");
  light.setColor(new RedColor(light));
 }
}

public class CarLight {
 public static void main(String[] args) {

  初始呼叫為紅燈

  light.showColor();
  //再調用為綠燈
  light.showColor();
  //再調用為黃燈
  light.showor();
 }
}

 

 

 

------------------------------ 享元模式(Flyweight) -- -----------------------------

(1)

主要用於創建物件時,運用共享技術,減少物件對記憶體的佔用.一個提高程序效率和性能的模式,會大大加快程序的運

行速度.
就是說在一個系統中如果有多個相同的對象,那麼隻共享一份就可以了,不必每個都去實例化一個物件。

Flyweight(享元)模式中常出現Factory模式。 Flyweight的內部狀態是用來共享的,Flyweight factory負責維護一個對

象儲存池(Flyweight Pool)來存放內部狀態的物件。

Flyweight的關鍵思路,在於:
新建對象時:
先到hashtable中進行獲取-->判斷獲取對像是否為空-->若是,則新建此對象,且放回hashtable -->若存在,則共享原來

的物件.

(2)

實例: (與靜態工廠模式進行對比)

public interface Car {

 public void showCarName();

}

Ⅰ)o

classCar implements showCarName()

 {
  System.out.println("this is the BMWCar .");

 }

}

class FordCar implements Car

{

 public voidoid foid; is the FordCar .");
 }
}

class CarFactory

{

 public static Car car;
 public static Car getCar(String 名稱= new BMWCar();
  }
  if("Ford".equals(name))

  {

   car =  new FordCar();

 

class CarFlyWeightFactory
{
    public  Car car;
    private Hashtable; carPool=new Hashtable();
 public  Car getCar(String name)
 {
  if("BMW".equals(name))
  { ==null)
   {
    car=new BMWCar();
    carPool.put(name, car);
   }   car=carPool.get( name);
   if(car==null)
   {
    car=new FordCar();
    carPool.put(name,       public int getNumber(){ return carPool .getSize(); }
}


公共類別測試{

公共靜態void main(string [] args){
carflyweightfactory carflyweightfactory = new CarflyWeightFactory(); carfly carf1 = carflyweightfactory.getCar( );
  汽車 carf2=carFlyWeightFactory.getCar("福特");
  carf2.showCarName();來的");
  }
  else
  {
   System.out.println("不同車來的");

  }

 
 }

}


輸出:
這是福特汽車。 ----職責鏈模式(責任鏈) -----------------------
(1)
責任鏈職責鏈模式:
為了避免請求的發送者和接收者之間的連結關係,使多個接受對像都有機會處理請求。
沿著鏈轉送請求,並保證接受者為隱式的,每個鏈上的物件都有一致的處理請求並存取鏈上後繼者的介面(即如下實例中,在自己方法中再呼叫一次)相同的)方法)。 // 是否有車
 private boolean hasHouse; // 是否有房
 private boolean hasResponsibility; // 是否有責任心

 public Boy() {
 }

 public Boy(boolean hasCar, boolean hasHouse, boolean hasResponsibility) {
  thishasuseCarp cahas;a; sponsibility ;
 }

 public boolean isHasCar() {

  return hasCar;
 }

 public void setHasCar(boolean hasCar) {

 public void setHasCar(boolean hasCar) {Ho

{

  return hasHouse;

 }

 public void setHasHouse(boolean hasHouse) {
  this.hasHouse = hasHouse;
 }

 public boolean isHasResResp() 返回public void setHasResponsibility(boolean hasResponsibility ) {

  this.hasResponsibility =有責任;
 }
}

public 介面 Handler {
  public void handleRequest(Boy boy);

}


public class HouseHandler 實作 Handler {

.  this.handler = handler;

 }

 public Handler getHandler() {
  return handler;
 }

 public void setHandler(Handler handler) {​​phandhad​​an v​​hklehhed C​​hhed​​hhad​​h ​​U​​hhhandlehhedh; boy) {
  if ( boy.isHasHouse()) {
   System.out.println("隨便到吧,我還有房子");

  } else {

   System.out.println("我也沒有房間");   System.out.println("我也沒有房間"); boy);
  }
 }

}


公共類CarHandler 實作Handler {

 原生Handler handler;


 public CarHandler(Handler handler) {dler} () {
return handler;

 }


 public void setHandler(Handler handler) {
  this.handler = handler;

 }

 public void handleRequest(Boy boy) {
  if (boy.isHasCar()) {
   System.out.println("呵呵,我有車"); 車");
   handler.handleRequest(boy);
  }
 }
}

public class ResponsibilityHandler implements Handler {

 private Handler ); this.handler = handler;

 }

 public Handler getHandler() {

  return handler;
 }

 public void setHandler(Handler handler) {

  .handler = handler; if (boy.isHasResponsibility( )) {
   System.out.println("我只有一顆帶Responsibility的心");
  } else {

   System.out.println("更沒有責任感");

   System.out.println("更沒有責任感");
   handler. }
 }

}


public class Girl {
 
 public static void main(String[] args) {
  ///  Boyy 也沒有房,但很負責任
 . false, true);
                // 也可使用setHanlder方法
  Handler handler = new CarHandler(new HouseHandler);
 }

}


==>
如何實例使請求沿著鏈在各接受對像中傳遞,當沒被第一個接受對象接受時,會傳遞給第二個對象,若被第一個對象接受了,則不傳遞下去:
1.各具體的接受對象採用這樣的構造方法:
public CarHandler(Handler handler) { this.handler = handler; }
2.各具體的接受對象實現接口的方法handleRequest()中.在調用時,若被接受,則執行true的內容,若不被接受,則執行false的內容,並繼續調用再調用handleRequest()方法.
3.在最後的測試類中,生成具體的handler時,用多層包含的形式.這樣,在調用了上一層car的方法後,會調用house的相應方法,最後再調用ResponsibilityHandler的方法.

==>前兩個handler是採用了有參數的構造方法,最後一個是採用了NULL的建構方法

------------------------------ 備忘錄模式(Memento) ------ -------------------------

(1)
備忘錄模式屬於行為型模式,其意圖是在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外保存這

個狀態,這樣以後就可以將物件恢復到原先保存的狀態。

(2)

實例如下:

有一個物件Employee.除了屬性外,還需要一個保存,還原狀態的方法.

有一個物件Memento,用來記錄Employee每一個時刻的狀態,

CareTaker,用來記錄保存,拿回Memento.需要一個保存,還原狀態的方法.->需要一個指標,一個容器.

package memento;
public class Memento{
    String name;
    int age;
    public Memento(String name,int age){
       this.name = name;
       this.age = age;
    }
}
登入後複製

Employee模式:

package memento;
public class Employee{
    private String name;
    private int age;
    public Employee(String aName,int aAge){
       name = aName;
       age = aAge;
    }
    public void setName(String aName){
       name = aName;
    }
    public void setAge(int aAge){
       age = aAge;
    }
    public Memento  saveMemento(){
       return new Memento(name,age);
    }
    public void restoreMemento(Memento memento){
       age = memento.age;
       name = memento.name;
    }
    public int getAge(){
       return age;
    }
    public String getName(){
       return name;
    }
}
登入後複製

CareTaker程式碼:

package memento;
import java.util.Vector;
public class CareTaker{
    private Vector v;
    private int  current;
    public CareTaker(){
       current = -1;
       v = new Vector();
    }
    public void setMemento(Memento mem){
       current ++;
       v.add(mem);
    }
    public Memento getMemento(){
       if(current>0){
           current --;
           return(Memento) v.get(current);
       }
       return null;
    }
}
登入後複製

Client程式碼:

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板