23種java設計模式

鴨脖發表於2012-09-30

Java中23種設計模式
目錄
1. 設計模式 3
1.1 建立型模式 4
1.1.1 工廠方法 4
1.1.2 抽象工廠 6
1.1.3 建造者模式 10
1.1.4 單態模式 13
1.1.5 原型模式 15
1.2 結構型模式 17
1.2.1 介面卡模式 17
1.2.2 橋接模式 19
1.2.3 組合模式 23
1.2.4 裝飾模式 26
1.2.5 外觀模式 29
1.2.6 享元模式 32
1.2.7 代理模式 34
1.3 行為型模式 37
1.3.1 責任鏈模式 37
1.3.2 命令模式 40
1.3.3 直譯器模式 43
1.3.4 迭代器模式 45
1.3.5 中介者模式 49
1.3.6 備忘錄模式 52
1.3.7 觀察者模式 54
1.3.8 狀態模式 58
1.3.9 策略模式 61
1.3.10 模板方法 63
1.3.11 訪問者模式 65

1. 設計模式(超級詳細)
1.1 建立型模式
AbstractFactory ( 抽象工廠 )
FactoryMethod ( 工廠方法 )
Singleton ( 單態模式 )
Builder ( 建造者模式 )
Protot*pe * 原型模式 )
1.1.1 工廠方法

    *義一個用於建立物件的介面,讓子類決定例項化哪一個類。FactoryMethod使一個類的例項*延遲到其子類。
 適用性

    1.當一個類不知道它所必須建立的物件的類的時候。

    2.當一個類希望由它的子類來指定它所建立的物件的時候。

    3.當*將建立物件的職責委託給多個幫助*類中的某一個,並且*希望將哪一個幫助子類是代理者這一資訊區域性化的時候。

 參與者

    1.Product
      定義工廠方法所建立的物件的介面。

    2.ConcreteProduct
      實現Product介面。

    3.Creator
      宣告工廠方法,該方法返回一個Product型別的物件*
      Creator也可以定義一個工廠方法的預設實現,它返回一個預設的ConcreteProduct物件。
      可以呼叫工廠方法以建立一個Product物件。

    4.ConcreteCreator
      重定義工廠方法以返回一個ConcreteProduct例項。
 類圖

 例子
*roduct

public interface Work {

    void doWork();
}
ConcreteProduct

public class StudentWork implements Work {

    public void doWork() {
        System.out.println("學生*作業!");
    }

}

public class TeacherWork implements Work {

    public void doWork() {
        System.out.println("老師審批作業!");
    }

}
Creator

public interface IWorkFactory {

    Work get*ork();
}
Concre*eCreator

pu*lic class StudentWorkFactory implements IWorkFactory {

    public Work getWork() {
        *eturn new StudentWork();
    }

}

public class TeacherWorkFactory implements IWorkFactory {

    public Work getWork() {
        return new TeacherWork();
    }

}
Test

public class Test {

    public static void m*in(Strin*[] args) {
        IWorkFactory studentWorkFactory = new StudentWorkFactory();
        studentWorkFactory.getWork().d*Work();
       
        IWorkFactory teacherWorkFactory * new TeacherWorkFactory();
        teacherWorkFactory.g*tWork().*oWork();
    }

}
result

學生做作業!
老師審批作業!
1.1.2 抽象工廠

    提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類。
 適用性

    1.一個系統要獨立於它的*品的建立、組合和表示時。

    2.一個系統要由多個產品系列中的一個來配置時。

    3.當你要強調一系列相關的產品物件的設計以便進行聯合使用時*

    4*當你提供一個產品類庫,而只想顯示它們*介面而不是實現時。

 參與者

    1.Ab*tractFactory
      宣告一個建立抽象產品物件的操作介面。

    2.ConcreteFactory
      實現建立具體產品物件的操作。

    *.AbstractProduct
      為一類產品物件宣告一個介面。

    4.ConcreteProdu*t
      定義一個將被相應的具體工廠建立的產品*象。
      實現*bstractProduct介面。

    5.Client
      僅使用由AbstractFactory和AbstractProduc*類宣告的介面
 類圖

 例子
*bstractFactory

public interface IAn*malFactory {

    ICat createCat();

    IDog cre*teDog();
}
ConcreteFactory

p*blic class BlackAnimalFactory implem*nts IAnimalFactory {

    public ICat createCat() {
        retur* new BlackCat();
    }

    public IDog createDog() {
        return new BlackDog();
    }

}

public class WhiteAnimalFac*ory imp*ements IAnimalFactory {

    public ICat createCat() {
        return new WhiteCat();
    }

    public IDog cre*teDog() {
        return new WhiteDog();
    }

}
Abstrac*Product

public interface ICat {

    void eat();
}

public interface IDog {

    void eat();
}
Concrete*roduct

public class Black*at implements ICat {

    public void eat() {
        System.out.println("The bl*ck cat is eating!");
    }

}

public class WhiteCat implements *Cat {

    public void eat() {
        Sy*tem.out.prin*ln("The w*ite cat is eating!*);
    }

}

public class BlackDog implements IDog {

    public void eat() {
        System.out.println("The black dog is eating");
    }

}

public class WhiteDog implements IDog {

    public void eat() {
        System.out.println("The white dog is eat*ng!");
    }

}
Client

public static void main(String[] args) {
    IAnimalFactory blackAnimalFa*tory = new BlackAnimalFactory();
    ICat blackCat = blackAnimalFactory.createCat();
    blackCat.eat();
    IDog blackD*g = blackAnimalFactory.createDog();
    blackDog.eat();
   
    IAnimalFactory whiteAnimalF*ctory = new WhiteAnimalFactory();
    ICat whiteCat = whiteAnimalFactory.createCat();
    whiteCat.eat();
    IDog *hiteDog = whiteAnimalFactory.createDog();
    whiteDog.eat();
}
res*lt

The bla*k cat is eating!
Th* black dog is eatin*!
The white cat is eating!
The white dog is *ating!
1.1.3 建造者模式

    將一個複雜物件的構*與它的表示分離,使*同樣的構建過程可以建立不同的表示。
 適用性

    1.當建立複雜物件的演算法應該獨立於該物件的組成部分以及它們的裝配方式時。

    *.當構造過程必須允*被構造的物件有不同*表示時。

 參與者

    1.Builder
      為建立一個Product物件的各個部件指定抽象介面。

    2.ConcreteBuilder
      實現Buil*er的介面以構造和裝配該產品的各個部件。
      定義並明確它所建立的表示*
      提供一個檢索產品的介面。

    3.Director
      構造一個使用Builder介面的物件。

    4.Product
      表示被構造的複雜物件。ConcreteBuilder建立該產品的內部表示並定義它的裝配過程。
      包含定義組成部件的類,包括將這些部件裝配成最終產品的介面。
 類圖

 例子
Buil*er

public interface PersonBuilder {

    void buildHead();
   
    v*id buildBody();
   
    void buildFoot()*

    Person buildPerson();
}
ConcreteBuilder

public class ManBuilder implements PersonB*ilder {

    Person person;
   
    public ManBuilder() {
        person = ne* Man();
    }
   
    publ*c void build*ody() {
        perso*.setBody("建造男人的身體");
    }

    public void buildFoot() {
        person.setFo*t("建造男人的腳");
    }

    public void buildHead() {
        pers*n.setHead("建造*人的頭");
    }

    *ublic Person buildPerson() {
        retur* person;
    }
}
Dir*ctor

public class PersonDirec*or {

    public Person constructPerson(PersonBuilder pb) {
        pb.buildHead();
        pb.buildBody();
        pb.buildFoot();
        return pb.buildPerson();
    }
}
Product

public class Person {

    private String head;
   
    private String body;
   
    private String foot;

    public String getH*ad() {
        return head;
    }

    public void setHead(String hea*) {
        this.head = head;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.b*dy = body;
    }

    public String getFoot() {
        return foot;
    }

    public void setFoot(String foot) {
        t*is.foot = foot;
    }
}

public class Man extends Person {

}
Test

publ*c class Test{
   
    public static void main(String[] ar*s) {
        PersonDirector pd = new PersonDirector();
        Person person = pd.constructPerson(new ManBuilder());
        System*out.println(person.getBody());
        System.out.println(person.getFoot());
        System.out.println(person.getHead());
    }
}
result

建造男人*身體
建造男*的腳
建造男人的頭
1.1.4 單態模式

    保證一個類僅有一個例項,*提供一個訪問它的全域性訪*點。
 適用性

    1.當類只能有一個*例而且客戶可以從一個眾所周知的訪問點訪問它時。

    2.當這個唯一例項應該是通過子類化可擴充套件的,並且客戶應該無需更改程式碼就能使用一個擴充套件的例項時。

 參與者

    Singleton
      定義一個Instance操作,允許客戶訪問它的唯一例項。Instance是一個類操作。
      可能負*建立它自己的唯一例項。
 類圖

 例子
Singleton

public class Singleton {
   
    private static Singleton sing;

    private Singleton() {
       
    }
   
    public st*tic Singleton get*nstance() {
        if (sing == null) {
            sing = new Singleto*();
        }
        return sing;
    }
}
Test

public class Test {
   
    public static void *ain(*tring[] args) {
        Singleton sing = Singleton.getInstance();
        Singleton si*g2 = Singleton.getI*stance();
       
        System.out.println(sing);
        System.out.pr*ntln(sing2);
    }
}
result

singleton.Singleton@1c78e57
singleton.Singleton@1c78e57
1.1.5 原型模式

    用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件。
 適用性

    1.當一個系統應該獨立於它的產品創*、構成和表示時。

    2.當要例項化的類是在執行時刻指定時,例如,通過動態裝載。

    3.為了避免建立一個與產品類層次平行的工廠*層次時。

    4.當一個類的例項只能有幾個不同狀態組合中的一種時。

    建立相應數目的原型並克隆它們可能比每次用合適的狀態手工例項化該類更方便一些。

 參與者

    1. Prototype
       宣告一個克隆自身的介面。

    2. ConcretePrototype
       實現一個克隆自身的操作。

    3. Client
       讓一個原型克*自身從而建立一個新的物件。
 類圖

 例子
Prototype

public class Prototype implements Cloneable {

    private String name;
   
    public void setName(String name) {
        this.name = name;
    }
   
    public String getName() {
        return this.name;
    }

    public Object clone(){
        try {
            return super.clone();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
ConcretePrototype

publ*c class ConcretePrototype extend* Prototype {

    public ConcretePrototype(String name) {
        setName(name);
    }
}
Client

public clas* Test {

    public static void main(String[] args) {
        Prototype pro = new ConcretePrototy*e("prototype");
        Prototype pro2 = (Prototype)pro.clone();
        *ystem.out.println(pro.getName()*;
        System.out.println(pro2.getName());
    }
}
result

prototype
prototype

1.2 結構型模式
Adapter * 介面卡模式 *
Bridge ( 橋接模* )
Composite ( 組合模式 )
Decorator ( 裝*模式 )
Facade ( 外觀模式 )
Flyweight ( 享元模式 )
Proxy ( 代理模式 )
1.2.1 介面卡模式

    將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面*相容而不能一起工作的那*類可以一起工作。
 適用性

    1.你想使*一個已經存在的類,而它的介面不符合你的需求。

    2.你想建立一個可以複用的類,該類可以與其他不相關的類或不可預見的類(即那*介面
      可能不一定相容的類)協同工作。

    *.(僅適用於物件Adapter)你想使用一些已經存在的子類,但是不可能對每一個都進行
      子類化以匹配它們的介面。物件介面卡可以適配它的父類介面。

 參與者

    1.Target
      定義Client使用的與特定領域相關的介面。

    2.Client
      與符合Target介面的物件協同。

    3.Adapt*e
      定義一個已經存在的介面,這個介面需要適配。

    4.Adapter
      對Adaptee的介面與Target介面進行適配
 類圖

 例子
Target

public interface Target {

    void adapteeMethod();
   
    void adapterMethod();
}
Adaptee

public class Adaptee {

    public void adapteeMethod() {
        Syste*.out.p*intln("Adaptee method!");
    }
}
Adapt*r

public clas* Adapter implement* Target {

    private Adap*ee adaptee;
   
    public Adapter(Adaptee adaptee) {
        this.adapte* = adaptee;
    }

public void adapteeMethod() {
adaptee.adapteeMethod();
}

public void adapterMethod() {
*ystem.out.println("Adapter method!");
    }
}
Client

public cla*s Test {

    public stati* void main(String[] args) {
        Target target = new Adapter(new Adaptee());
        tar*et.adapteeMethod();
       
        target.adapterM*thod();
    }
}
result

Adaptee method!
Adapter method!
1.2.2 橋接模式

    將抽象部分與它*實現部分分離,使它們都可以獨立地變化。
 適用性

    1.你不希望在抽*和它的實現部分之間有一個固定的繫結關係。
      例如這種情況可能是因為,在程式執行時刻實現部分應可以*選擇或者切換。

    2.類的抽象以及它的實現都應該可以通*生成子類的方法加以擴充。
      這時Bridge模式使你可以對不同的抽象介面和實現部分進行組合,並分別對它們進行擴充。

    3.對一個抽象的實現部分的修改應對客戶不產生影響,即客戶的程式碼不必重新編譯。

    4.正如在意圖一節的第一個類圖中所示的那樣,有許多類要生成。
      這*一種類層次結構說明你必須將一個物件分解成兩個部分。

    5.*想在多個物件間共享實現(可能使用引用計數),但同時要求客戶並不知*這一點。

 參與者

    1.Abstraction
      定義抽象類的介面。
      維護一個指向Implementor型別物件的指標。

    2.RefinedAbstraction
      擴充由Abstraction定義的介面。

    3.Implementor
      定義實現類的介面,該介面不一定要與Ab*traction的介面完全一致。
      事實上這兩個介面可以完全不同。
      *般來講,Implementor介面僅提供基本操作,而Abstraction則定義了基於這些基本操作的較高層次的操作。

    4.ConcreteImplementor
      *現Implementor介面並定義它的具體實現。
 類圖

 例子
Abstr*ction

public abstract class Person {

    private Clothing clothing;
   
    pr*vate String type;

    public Clothing getClothing() {
        return clothing;
    }

    publi* void setClothing() {
        this.clothing = *lothingFactory.getClothing();
    }
   
    public void setType(String type) {
        t*is.type = type;
    }
   
    public String getType() {
        return this.ty*e;
    }
   
    public abstract void dress();
}
RefinedAbstraction

public class Man extends *erson {
   
    public Man() {
        setType("男人");
    }
   
    public void dress() {
        Clothing clothing = get*lothing();
        clothing.personDressCloth(this);
    }
}

public class Lady extends Person {

    public Lady() {
        setTyp*("女人");
    }
   
    public void dress() {
        Cloth*ng clothing = getClothing();
        c*othing.personDressCloth(this);
    }
}
Implemento*

public abstract class Clothing {

    public abstract void personDressC*oth(*erson person);
}
ConcreteImplemento*

public class *ack*t extends Clothing {

    public void personDressCloth(Person person) {
        System.out.println(person.getType() + "穿馬甲");
    }
}

public cl*ss Trouser extends Clothing {

    public void personDressCloth(Person person) {
        System.ou*.println(*erson.getType() + "穿褲子");
    }
}
Test

public class Te*t {

    public s*atic void main(String[] args) {
       
        Person man = new Man();
       
        Person lady = new Lady();
       
        Clothing jacket = new Ja*ket();
       
        Clot*ing trouser = new Trouser();
       
        jacket.personDressCloth(man);
        trouser.personDressCloth(man);

        j*cket.personDressCloth(lady);
        trouser.personDressCloth(lady);
    }
}
result

男人穿馬甲
男人穿褲子
女人穿馬甲
女人穿褲子
1.2.3 組合模式

    將物件組合成樹形結構以表示"部分-整體"的層次結構。"Composite使得使用者對單個物件和組合對*的使用具有一致性。"
 適用性

    1.你想表示物件的部分-整*層次結構。

    2.你希望使用者忽略組合物件與單個物件的不同,使用者將統一地使用組合結構中的所有物件。

 參與者

    1.Component
      為組合中的物件宣告介面。
      在適當的情況下,實現所有類共有介面的預設行為。
      宣告一個介面用於訪問和管理Component的子元件。
      (可選)在遞迴結構中定義一個介面,用於訪問一個父部件,並在合*的情況下實現它。

    2.Leaf
      在組合中表示葉節點物件,葉節點沒有子節點。
      在組合中定義節點物件的行為。

    3.Compos*te
      定義有子部件的*些部件的行為。
      儲存子部件。
      在Component介面中實現與子部件有*的操作。

    4.Client
      通過Component接*操縱組合部件的物件。
 類圖

 例子
Component

p*blic abstract class Employer {

    private String name;
   
    public void setName(String name) {
        this.name = *ame;
    }
   
    public String getName() {
        return this.name;
    }
   
    public abstract void add(Employer employer*;
   
    public abstract void delete(Employer employer);
   
    public List employers;
   
    public void printInfo*) {
        System.out.println(name);
    }
   
    *ublic List getE*ployers() {
        return this.employers;
    }
}
Leaf

public class Programmer extends Employer {

    public Programmer(String name) {
        setNam*(name);
        employers = null;//程式設計師, 表示沒有下屬了
    }

    public v*id add(Employer employer) {
       
    }

    public void delete(Employer employer) {
       
    }
}

public class Pro*ectAssistant extends Employer {

    public ProjectAss*stant(String name) {
        setName(name);
        employers = *ull;//專案助理, 表示沒有下屬了
    }

    public void add(Employer employer) {
       
    }

    public void delet*(Employer employer) {
       
    }
}
Composite

public class Project*anager extends E*ployer {
   
    public ProjectManager(String name) {
        setName(name);
        employers = new A*rayList();
    }
   
    public void add(Employer employer) {
        employers.add(employer);
    }

    public void delete(Emplo*er employer) {
        employers.remove(employer);
    }
}
Clie*t

publ*c class Test {

    public st*tic void main(String[] args) {
        Employer pm = new ProjectManager("專案經理");
        Emplo*er pa = new ProjectAssistant("專案助理");
        Employer progra*mer1 = new Programmer("程式設計師一");
        Employer programmer2 = new Programmer("程式設計師二");
       
        pm.add(pa);//為專案經理新增專案助理
        pm.add(programmer2);//*專案經理*加程式設計師
       
        List ems = pm.getEm*loyers();
        for (Employer em : ems) {
            System.out.println(em.getNam*());
        }
    *
}
result

專案助理
程式設計師二
1.2.4 裝飾模式

    動態地給一個物件新增一些額外的職責。就增加功能來說,Decorator模*相比生成子類更為*活。
 適用性

    1.在不影響其他*象的情況下,以動態、透明的方式給單個物件新增職責。

    2.處理那些可以撤消的職責。

    3.當不能採用生成子類的方法進行擴充時。

 參與者

    1.Component
      定義一個物件介面,可以給這些物件動態地新增職責。

    2.ConcreteComponent
      定義一個物件,可以給這個物件新增一些職責。

    3.Decorator
      維持一個指向Component物件的指標,並定義一個與Component介面一致的介面。

    4.ConcreteDecorator
      向元件新增職責。
 類圖

 例子
Component

public interface Person {

    void eat();
}
ConcreteComponent

*ublic class M*n implements Person {

public void eat() {
System.out.println("男人在吃");
*
}
Decorator

public abstrac* class Decorator implements Perso* {

    protected Person person*
   
    public void setPerson(Person person) {
        this.person = person;
    }
   
    public void eat() {
        person.eat();
    }
}
ConcreteDec*rator

publi* class ManDecoratorA extends Decorator {

    public void eat() {
        super.eat();
        reEat();
        Sy*tem.out.println("ManDecoratorA類");
    }

    public void reEat() {
        System.out.println("再吃一頓飯");
    *
}

public class ManDecoratorB extends Decorator *
   
    public void eat() {
        super.eat();
        Syst*m.out.println("===============");
        System.out.println("ManDecoratorB類");
    }
}
Test

public class Test {

    public st*tic void main(Strin*[] args) {
        Man man = new Man();
        ManDecoratorA md1 = new ManDecoratorA();
        ManDecoratorB md2 = n*w ManDecoratorB();
       
        md1.setPerson(man);
        md2.setPerson(md1);
        md2.eat();
    }
}
result

男人在吃
再吃一頓飯
ManDecoratorA類
===============
ManDecoratorB類
1.2.5 外觀模式

    為子系統中的一組介面提供一個一致的介面,Facade模式定義了一個高層介面,這個介面使得這*子系統更加容易使用。
 適用性

    1.當你要為一個*雜子系統提供一個簡單介面時。子系統往往因為不斷演化而變得越來越
      複雜。大多數模式使用時都會產生更多更小的類。這使得子系統更具可重用性,也更容
      易對子系統進行定製,但這也給*些不需要定製子系統的使用者帶來一些使用上的困難。
      Fa*ade可以提供一個簡單的預設檢視,這一檢視對大多數使用者來說已經足*,而那些需
      要更多的可定製性的使用者可以越過facade層。

    2.客戶程式與抽象類的實現部分之間存在著很大的依賴性。引入facade將這個子系統與客
      戶以及其他的子系統分離,可以提高子系統的獨立性和可移植性。

    3.當你需要構建一個層次結構的子系統時,使用facade模式定義子系統中每層的入口點。
      如果子系統之間是相互依賴的,你可以讓它們僅通過facade進行通訊,從而簡化了它們
      之間的依賴關係。

 參與者

    1.Facade
      知道哪些子系統類負責處理請求。
      將客戶的請求代理給適當的子系統物件。

    2.Subsystemclasses
      實現子系統的功能。
      處理由Facade物件指派的任務。
      沒有facade的任何相關資訊;即沒有指向*acade的指標。
 類圖

 例子
Facade

publi* class Facade {

    ServiceA s*;
   
    ServiceB sb;
   
    ServiceC sc;
   
    public Facade() {
        sa = new S*rviceAImpl();
        sb = new *erviceBImpl();
        sc = new ServiceCImpl();
    }
   
    public void methodA() {
        sa.methodA();
        sb.methodB();
    }
   
    publi* void methodB() {
        s*.methodB();
        sc.methodC();
    }
   
    public void methodC() {
        sc.methodC();
        sa.methodA();
    }
}
Subsystemclasse*

public *lass ServiceAImpl implements ServiceA {

    public void methodA() {
        System.out.println("這是服務A");
    }
}

public class ServiceBImpl implements ServiceB {

    public void methodB() {
        System.out.println("這是服務B");
    *
}

public class ServiceCImpl implements ServiceC {

    public void methodC() {
        System.out.println("這是服*C");
    }
}
Test

public class Test {
   
    public static voi* main(String[] args) {
    ServiceA sa = new ServiceAImpl();
    Ser*iceB sb = new ServiceBImpl();
       
        sa.metho*A();
        sb.methodB();
       
        System.out.println("========");
        //facade
        Facade facade = new Facade();
        facade.methodA();
        facade.methodB();
    }
}
resu*t

這是服務A
這是*務B
========
這是服務A
這是服務B
這是服務B
這是服務C
1.2.6 享元模式

    運用共享技術有效地支援大量細粒度的物件。
 適用性

    當都具備下列情況時,使用Flyweight模式:

    1.一個應用程式使用了大量的*象。

    2.完全由於使用大量的物件,造成很大的儲存開銷。

    3.物件*大多數狀態都可變為外部狀態。

    4.如果刪除物件的外部狀態,那麼可以*相對較少的共享物件取代很多組物件。

    5.應用程式不依賴於物件標識。由於Flyweight物件可以被共享,對於*念上明顯有別的物件,標識測試將返回真值。

 參與者

    1.Flyweight
      描述一個介面,通過這個介面flyweight可以接受並作用於外部狀態。

    2.ConcreteFlyweight
      實現Flyweight介面,併為內部狀態(如果有的話)增加儲存空間。
      Concrete*lyweight物件必須是可共享的。它所儲存的狀態必須是內部的;即,它必須獨立於ConcreteFlyweight物件的場景。 www.2cto.com

    3.UnsharedConcreteFlyweigh*
      並非所有的Flywe*ght子類都需要被共享。Flyweight介面使共享成為可能,但它並不強制共*。
      在Flyweight物件結構的某些層次,UnsharedConcreteFlyweight物件通常將ConcreteFlyweight物件作為子節點。

    4.Flyweigh*Factory
      建立並管理flywe*ght物件。
      確保合理地共享flyweight。當使用者請求一個flywei*ht時,Fl*weightFactory物件提供一個已建立的例項或者建立一個(如果不存在的話)。
 類*

 例子
Flyweight

public int*rface Flyweight {

    void a*tion(int arg);
}
ConcreteFlyweight

public class FlyweightImpl implements Flyweight {

    public void action(int arg) {
        // T*DO Auto-genera*ed method stub
        System.out.println(*引數值: " + arg);
    }
}
FlyweightFactory

public class Flyweigh*Factory {

    private static Map flyweights = new HashMap();
   
    public FlyweightF*ctory(String arg) {
        flyweights.put(arg, new FlyweightImpl());
    }
   
    public static Flyweight getFly*eight(String key) {
        if (flyweights.get(key) == null) {
            flyweights.p*t(key, new FlyweightImpl());
        }
        return flyweights.get(key);
    }
   
    public static int g*tSize() {
        retu*n flyweights.size();
    }
}
Test

public class Test {

    public static v*id main(String[] args) {
        // TODO Auto-generated method stub
        Flyweight fly1 = Flyw*ightFact*ry.getFlyweight(*a");
        fly1.action(1);
       
        Flyweight fly* = FlyweightFactory.getF*yweight("a");
        System.out.println(fly1 == fly2);
       
        Flyweight fl*3 = FlyweightFactory.getFlywei*ht("b");
        fly3.action(2);
       
        Flyweight fly4 = Flyweigh*Factory.getF*yweight("c");
        fly4.action(3);
       
        Flyweigh* fly5 = FlyweightFactory.getFlyweight("d");
        fly4.action(4);
       
        System.out.println(FlyweightFactory.getSize())*
    }
}
result

引數值: 1
true
引數值: 2
*數值: 3
引數值: 4
4
1.2.7 代理模式

    為其他物件提供一種代理以控制對這個物件的訪問。
 適用性

    1.遠端代理(RemoteProxy)為一個物件在不同的地址空間提供區域性代表。

    2.虛*理(VirtualProxy)根據需*建立開銷很大的物件。

    3.保護代理(ProtectionProxy)控制對原始物件的訪問。

    4.智慧指引(SmartReference)取代了簡單的指標,它在訪問物件時執行一些附加操作。

 參與者

    1.Proxy
      儲存一個引用使得代理可以訪問實體。若RealSubject和Subject的介面相同,Proxy會引用Subject。
      *供一個與Subject的介面相同的介面,這樣代理就可以用來替代實體。
      控制對實體的*取,並可能負責建立和刪除它。
      其他功能依賴於*理的型別:

    2.RemoteProxy負責對請求及其引數進行編碼,並向不同地址空間中的實體傳送已編碼的請求。

    *.VirtualProxy可以快取實體的附加資訊,以便延遲對它的訪問。

    4.ProtectionProxy檢查呼叫者是*具有實現一個請求所必需的訪問許可權。

    5.Subjec*
      定義RealSubject和Proxy的共用介面,這樣就在任何使用RealSubject的地方都*以使用Proxy。

    6.RealSubject
      *義Proxy所代表的實體。
 類圖

 例子
Proxy

public class ProxyObject implements Object {

    Objec* obj;
   
    public ProxyObject() {
        System.out.println("這是代理類");
        o*j = new ObjectImpl();
    }
   
    public void ac*ion() {
        System.out.p*intln("代理開始");
        obj.action*);
        System.out.println(*代理結束");
    }
}
Subject

public interface Obje*t {

    void action();
}
RealSubject

public class ObjectImpl implements Object {

    pu*lic void action() {
        System.out.println("========");
        System.out.println("========");
        System.out.pr*ntln("這是被代理的類");
        System.out.println("========");
        System.out.println("========");
    }
}
Test

public class Test {

    publi* static void main() {
    Object ob* = new ProxyObject();
        obj.action();
    *
}
result

這是代理類
代理開始
========
=*======
這是被代理的類
========
======*=
代理結束
1.3 行為型模式
Chain of Responsibility ( 責任鏈模式 )
Command ( 命令模式 )
Interpreter ( 直譯器模式 )
Iterator ( 迭代器*式 )
Mediator ( 中介者模式 )
Memento ( 備忘錄模式 )
Observer ( 觀察者模式 )
State ( 狀*模式 )
Strategy ( 策略模式 )
TemplateMethod ( 模板方法 )
Vis*tor ( 訪問者模式 )
1.3.1 責任鏈模式

    使多個物件都有機會處理請求,從而避免請求的傳送者和接收者之間的耦合關係。將這些物件連成一*鏈,
    並*著這條鏈傳遞該請求,直到有一個物件處理它為止。
   
    這一模式的想法是,給多個物件處理一個請求的機會,從而解耦傳送者和接受者.
 適用性

    1.有多個的物件可以處理一個請求,哪個物件處理該請求執行時刻自動確定。

    2.你*在不明確指定接收者的情況下,向多個物件中的一個提交一個請求。

    3.可處理一個請求的物件集合應被動態指定。

 參與者

    1.Handler
      定義一個處理請求的介面。
      (可選)實現後繼鏈。

    2.ConcreteHandler
      處理它所負責的請*。
      可訪問它的後繼者。
      如果可處理該*求,就處理*;否則將該請求轉發給它的後繼者。

    3.Client
      向鏈上的具體處理者(ConcreteHandler)物件提交請求。
 類圖

 例子
Hand*er

public interface RequestHandle {

    void handleRequest(R*quest request);
}
ConcreteHandler

public class HRRequestHandle implements RequestHandle {

    public void handleRequest(Request request) {
        if (request instanceof DimissionRequest) {
            System.out.println("要離職, 人事審批!");
        }

        System.out.println("請求完*");
    }
}

public class PMRequestHandle implements RequestHandle {

    Req*estHandle rh;
   
    public PMRequestHandle(RequestHandle *h) {
        this.rh = rh;
    }
   
    public void handle*equest(Request request) {
        if (request instanceof AddMoneyRequest) {
            System.out.println("要加薪, 專案經理審批!*);
        } else {
            rh.handleRequest(request);
        }
    }
}

public class TLRequestHandle implements RequestHandle {

    RequestHandle rh;
   
    public TLRequestHandle(RequestHand*e rh) {
        this.rh = rh;
    }

    public void handleRequest(Request request) {
        if (request instanceof LeaveRe*uest) {
            System.ou*.println("要請假, 專案組長審批!");
        } else {
            rh.handleRequest(request);
        }
    }
}
Client

public *lass Test {

   
    public static v*id main(String[] args) {
        RequestHa*dle hr = *ew HRRequ*stHandle();
        Requ*stHandle pm = new P*RequestHandle(hr);
        RequestHandle tl = new TLRequestHandle(pm);
       
        //team leader處理離職請求
        Request request = new DimissionRequest()*
        tl.handleRequest(request);
       
        System.out.println("===========");
        //team leader處理加薪請求
        request = new AddMoneyRequest();
        tl.handleRequ*st(request);
       
        System.out.println("========");
        //專案經理上理辭職請求
        requ*st = ne* Dimissio*Request();
        pm.handleRequest(request);
    }
}
result

要離職, 人事審批!
請求完畢
=======*===
要加薪, 專案經理審批!
========
要離職, 人事審批!
請求完畢
1.3.2 命令模式

    將一個請求封裝為一個物件,從而使你可用不同的請求對客戶進行引數化;對請求排隊或記錄請求日誌,以及支援可撤消的*作。
 適用性

    1.抽象出待執行的動作以引數化某物件。

    2.在不同的時刻指定、排列和執行請求。

    3.支援取消操作。

    4.支援修改日誌,這樣當系統崩潰時,這*修改可以被重做一遍。

    5.用構建在原語操作上的高層操作構造一個系統。

 參與者

    1.Comma*d
      宣告執行操作的介面。

    2.ConcreteCommand
      將一個接收者物件繫結於一個動作。
      呼叫接收者相應的操作,以實現Execute。

    3.Client
      建立一個具體命令物件並設定它的接收者。

    4.Invoker
      要求該命令執行這個請求。

    5.Recei*er
      知道如何實*與執行一個請求相關的操作。任何類都可能作為一個接收者。
 類圖

 例子
Command

public abstract class *ommand {
   
    protecte* Receiver receiver;
   
    public Command(Receiver re*eiver) {
        this.receiver = receiver;
    }
   
    public abstract *oid execute();
}
ConcreteCommand

public class CommandImpl extends Comman* {

    public CommandImpl(Receiv*r receiver) {
        super(receiver);
    }
   
    pu*lic void *xecute*) {
        receiver.request();
    }
}
Invoker

public cl*ss Invoker {

    private Command command;
   
    pub*ic void setCommand(Command c*mmand) {
        this.command = command;
    }
   
    public void execute*) {
        command.execute();
    }
}
Receiver

public class Receiver {

    public void receive() {
        S*stem.out.println("This is Receive class!");
    }
}
Test

publ*c class Test {

    pub*ic static void main*String[] args) {
        R*ceiver rec = new Receiver();
        Command cmd = n*w CommandImpl(rec);
        Invoker i = new Invoker();
        i.setCom*and(cmd);
        i.execut*();
    }
}
result

This is Receive class!
1.3.3 直譯器模式

    給定一個語言,定義它的文法的一種表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。
 適用性

    當有一個語言需要解釋執行,並且你可將該語言中的句子表示為一個抽象語法樹時,可使
    用直譯器模式。而當存在*下情況時該模式效果最好:

    1.該文法簡單對於複雜的文法,文法的*層次變得龐大而無法管理。

    2.效率不是一個關鍵問題最高效的直譯器通常不是通過直接解釋語法分析樹實現的,而是首先將它們轉換成另一種形式。

 參與者

    1.AbstractExpression(抽象表示式)
      宣告一個抽象的解釋操作,這個介面為抽象語法樹中所有的節點所共享。

    2.TerminalExpression(終結符表示式)
      實現與文法中的終結符相關聯的解釋操作。
      一個句子中的每個終結符需要該類的一個例項。

    3.N*nterminalExpression(非終結符表示式)
      為文法中的非終結符實現解釋(Interpret)操作。

    4.Context(上下文)
      包含直譯器之外的一些全域性資訊。

    5.Client(客戶)
      構建(或被給定)表示該文法定義的語言中*個特定的句子的抽象*法樹。
      該抽象語法樹由NonterminalExpression和TerminalExpression的例項裝配而成。
      呼叫解*操作。
 類圖

 例子
AbstractExpression

pu*lic abstract class Expression {

    abstract void interpret(Context ctx);
}
Expression

public class AdvanceExpressio* extends Expression {

    void interpr*t(Context ctx) {
        System.out.println("這是高階解析器!");
    }
}

public class SimpleExpression extends Expressio* {

    void interpret(*ontext ctx) {
        System.out.pri*tln("這是普通解析器!");
    }
}
Context

public class Co*text {

    private S*ring content;
   
    *rivate List list = new ArrayList();
   
    public void setContent(String content) {
        this.content = content;
    }
   
    pu*lic String getContent() {
        return this.con*ent*
    }
   
    public void add(Expression ep*) {
        list.add(eps);
    }
   
    public List getList() {
        return list;
    }
}
Test

public class Test {

    public static void main(String[] args) {
        Context *tx = new Context();
        ctx.*dd(new SimpleExpression());
        ctx.add(new AdvanceExpression());
        ctx.add(new SimpleExpression());
       
        for *Expression eps : ctx.getL*st()) {
            eps.interpret*ctx);
        }
    }
}
res*lt

*是普通解析器!
這是高階解析器!
*是普通解析器!
1.3.4 迭代器模式

    給定一個語言,定義它的文法的一種表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。
 適用性

    1.訪問一個聚合物件的內容而無需暴露它的內部表示。

    2.支援對聚合物件的多種遍歷。

    3.為遍歷不同的聚合結構提供一*統一的介面(即,支援多型迭代)。

 參與者

    1.Iterator
      迭代器定義訪問和遍歷元素的介面。

    2.ConcreteIterator
      具*迭代器實現迭代器介面。
      對該聚合遍歷時跟蹤當前位置。

    3.Aggregate
      聚合定義建立相應迭代器*象的介面。

    4.ConcreteAggregate
      具體聚合實現建立相應迭代器的介面,該操作返回ConcreteIterator的一個適當的例項.
 類圖

 例子
Iterator

public interface Iterator {

    Object nex*();
   
    void first();
   
    voi* last();
   
    boolean hasNext();
}
ConcreteIterator

public class IteratorImpl implements It*rator {

    private List list;
   
    private int index;
   
    public Ite*atorImpl(List list* {
        index = 0;
        this.list = list;
    }
   
    public void first() {
        index = 0;
    }

    publ*c void last() {
        index = list.getSize();
    }

    public Object next() {
        Object obj = list.get(index);
        index++;
        ret*rn obj;
    }

    public boolean hasNext() {
        return index < list.getSize();
    }
}
Aggregate

p*blic interface List {

    Iterator iterator();
   
    Object get(int index);
   
    int *etSize();
   
    void add(Object ob*);
}
ConcreteAggregate

public class ListImpl implements List {

    private Object[] list;
   
    private int index;
   
    private int size;
   
    public ListImpl() {
        index = 0;
        size = 0;
        list = new Object[100];
    }
   
    public Iterator iterator() {
        return new IteratorImpl(this);
    }
   
    public O*ject get(int index) {
        return list[index];
    }
   
    public int getSize() {
        return this.size;
    }
   
    public void add(Object obj) {
        list[index++] = obj;
        size++;
    }
}
Test

public class Test {

    public stati* void main(String[] arg*) {
        List list = new ListImpl();
        list.add("a");
        list.add("b");
        list.add("c");
        //第一種迭代方式
        Iterator it = list.iterator();
        while (*t.ha*Next()) {
            S*stem.out.println(it.next());
        }
       
        Syst*m.out.println("=====");
        //第二種迭代方式
        for (int i = 0; i < list.getSize(); i++) {
            System.out.println(list.get(i));
        }
    }
}
result

a
b
c
=====
a
b
c
1.3.5 中介者模式

    用一箇中介物件來封裝一系列的物件互動。中介者使各物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。
 適用性

    1.一組物件以定義良好但是複雜的方式進行通訊。產生的相互依賴關係結構混亂且難以理解。

    2.一個物件引用其他很多物件並且直接與這些物件通訊,導致難以復*該物件。

    3.想定製一個分佈在多個類中的行為,*又不想生成太多的子類。

 參與者

    1.Mediator
      中介者定義一個介面用於與各同事(Colleague)物件通訊。

    2.ConcreteMediator
      具*中介者通過協調各同事物件實現協作行為*
      瞭解並維護它的各個同事。

    3.Colleagueclass
      每一個同事類都知道它的中介者物件。
      每一個同事物件在需與其他的同事通訊的時候*與它的中介者通訊
 類圖

 例子
Mediator

public abstract class Mediator {

    public abstract void notice(String content);
}
ConcreteMediator

public *lass ConcreteMediator e*tends Mediator {

    private ColleagueA ca;
   
    pri*ate ColleagueB cb;
   
    public ConcreteMediator() {
        ca = new ColleagueA();
        cb = new Col*eagueB();
    }
   
    public void no*ice(String content) {
        if (co*tent.equals("boss")) {
            //老闆來了, 通知員工A
            ca*action();
        }
        if (content.equals("client")) {
            //客戶來了, *知前臺B
            cb.action();
        }
    }
}
Colleagueclass

public class ColleagueA extends *olleague {

   
    public void action(* {
        System.out.println("普通員工努力工作");
    }
*

public class ColleagueB extends Colleague {

    public void action() {
        System.out.println("前臺注意了!");
    }
}
Test

public class Test {

    public static void main(String[] args) {
        Mediator med = new Concr*teMediator();
        */老闆來了
        med.notice("boss");
       
        //客戶來*
        med.n*tice("client");
    }
}
result

普通員工努力工作
前臺注意了!
1.3.6 備忘錄模式

    在不破壞封裝性*前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。
 適用性

    1.必須*存一個物件在某一個時刻的(部分)狀態,這樣以後需要時它才能恢復到先前的狀態。

    2.如果一個用介面來讓其它物件直接得到這些狀態,將會暴露物件的實現細節並破壞物件的封裝性。

 參與者

    1.Memento
      備忘錄儲存原發器物件的內部狀態。

    2.Originator
      原發器建立一個備忘錄,用以記錄當前時刻*的內部狀態。
      使用備忘錄恢復內部狀態.

    3.Caretaker
      負責儲存好備忘錄。
      不能對備忘錄的內*進行操作或檢查。
 類圖

 例子
Memento

public class Memento {

    private String state;

    public Meme*to(String state) {
        this.state = state;
    }

    public String getState() {
        *eturn state;
    }

    public void setSt*te(String state) {
        this.stat* = s*ate;
    }
}
Or*ginator

public class Originator {

    private String state;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
   
    *ublic Memento createMemento() {
        return new Memento(state);
    }
   
    p*blic void setMemento(Memento meme*to) {
        state = memento.ge*State();
    }
   
    p*blic void showState(){
        System.out.println(state);
    }
}
Caretaker

public class Caretaker {
   
    p*ivate Memento memento;
   
    public Memento getMemento(){
        return this.memento;
    }
   
    public void setMemento(Memento memento){
        this.memento = memento;
    }
}
Test

public class Test {

    public static void main(String[] args) {
        Originator org = *ew Originator();
        org*setState("開會中");
       
        C*retaker ctk = new Ca*etaker();
        ctk.setMemento(org.createMemento());//將資料封裝在Caretaker
       
        or*.setState("睡覺中");
        org.sh*wState();*/顯示
       
        org.setMemento(ctk.getMemento());//將資料重新匯入
        or*.showState();
    }
}
result

睡覺中
開會中
1.3.7 觀察者模式

    定義物件間的一種一*多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。
 適用性

    1.當一個抽象模型有兩個方面,其中一個方面依賴於另一方面。
      將這二者封裝*獨立的物件中以使它們可以各自獨立地改變和複用。

    2.當對一個物件的改變需要同時改變其它物件,而不知道具體*多少物件有待改變。

    3.當一個物件必須通知其它物件,而它又不能假定其它物件是誰。

 參與者

    1.Subject(目標)
      目標知道它的觀*者。可以有任意多個觀察者觀察同一個目標。
      提供註冊和刪除觀察者物件的介面。

    2.Obser*er(觀察者)
      為那些在目標發生改變時需獲得*知的物件定義一個更新*口。

    3.ConcreteSubject(具體目標)
      將有關狀態存入各ConcreteObserver物件。
      當它的狀態發生改變時,向它的各個觀察者發出通知。

    4.ConcreteObserver(具體觀察者)
      維護一個指向ConcreteSubject物件的引用。
      儲存有關狀態,這些狀態應與目標的狀態保持一致。
      實現Observer的更新介面*使自身狀態與目標的狀態保持一致
 類*

 例子
Subject

public abstract class Citizen {
   
    List po*s;
   
    String help = "normal";
   
    public void setHelp(String help) {
        this.help = *elp;
    }
   
    public String getHelp() {
        return this.help;
    }
   
    abstract void sendMessage(String help);

    public void setPolicemen() {
        t*is.pols = new ArrayList();
    }
   
    public void register(*oliceman pol) {
        this.pols.add(pol);
    }

    public void unRegister(Policeman pol) {
        this.pols.remove(pol);
    }
}
Observer

public interface Policeman {

    void action(Citizen ci);
}
*oncreteSubjec*

public class Hua*gPuCitizen extends Citiz*n {

    public HuangPuCitizen(P*liceman pol) {
        setPolicemen();
        register*pol);
    }
   
    public void sendMessage(String help) {
        setHelp(h*lp);
        for(int i = 0; i < pols.size(); i++) {
            Policeman pol = pols.get(i);
            //通知警察行動
            pol.action(this);
        }
    }
}

public class TianHeCitizen extends Citizen {

    public TianHeCitizen(Policeman pol) {
        setPolicemen();
        re*ister(pol);
    }
   
    public void sendM*ssage(Str*ng help) {
        setHelp(help);
        for (i*t i = 0; i < pols.size(); i++) {
            Policeman pol = pols.get(i);
            //通知警察行動
            pol.action(this);
        }
    }
}
ConcreteObserver

public clas* HuangPuPoliceman implements Pol*ceman {

    public void action(Citizen ci) {
        String help = ci.getHelp();
        if (help.equals("normal")) {
            System.o*t.println("一切正常, 不用出動");
        }
        if (help.*quals("unnormal")) *
            System.out.println("有犯罪行為, 黃埔警察出動!");
        }
    }
}

public c*ass TianHePoliceman implements Policem*n {

    public void action(Citizen ci) {
        String help = *i.getHelp();
        if (help.equals("*ormal")) {
            System.out.println("一切正常, 不用出動");
        *
        if (help.equals("unnormal")) {
            System.out.println("有犯罪行為, 天河警察出動!");
        }
    }
}
Test

public class Test{

    public st*tic void main(String[] args) {
        Policeman thPol = new TianHePoliceman();
        Pol*ceman hpPol = new HuangPuPoliceman();
       
        Ci*izen citizen = new HuangPuCitizen(hpPol);
        citizen.sendMessage("unnormal");
        citizen.sendMessage("normal");
       
        System.out.println("===========");
       
        citizen = new TianH*Citizen(thPol);
        citizen.sendMessage("normal");
        citi*en.sendMessage("unnormal");
    }
}
result

有犯罪行為, 黃埔警察出動!
一切正常, 不用出動
======*====
一切正常, 不用出動
有犯罪行為, 天河警察出動!
1.3.8 狀態模式

    定義物件間*一種一對多的依賴關係,當一個物件的狀態*生改變時,所*依賴於它的物件都得到通知並被自動更新。
 適用性

    1.一個物件的行為取決於它的狀態,並且它必須在執行時刻根據狀態改*它的行為。

    2.一個操作中含有龐大的多分支的條件語句,且這些分支依賴於該物件的狀態。
      這個狀態通常用一個或多個列舉常量表示。
      通常,有多個操作包含這一相同的條件結構。
      State模式將每一個條件分支放入一個獨立的類中。
      這使得你可以根據物件自身的情況將物件的狀態作為一個物件,這一物件可以不依賴於其他物件而獨立變化。

 參與者

    1.Context
      定義客戶感興趣的介面。
      維護一個ConcreteState子類的例項,這個例項定義當前狀態。

    2.State
      定義一個介面以封裝與Context的一個特定狀態相關的行為。

    3.ConcreteStatesubclasses
      每一子類實現一個與Context的一個狀態*關的行為。
 類圖

 例子
*ontext

pu*lic class Context {

    private Weather weather;

    public voi* setWeather(Weather weather) {
        this.*eather = weather;
    }

    pu*lic Weather getWeather() {
        return this.weather;
    }

    public String weatherMessage() {
        return w*ather.getWeather();
    }
}
State

public interface Weath*r {

    St*ing getWeather();
}
Concrete*tatesubclasses

public class Rain implements Weather {

    public Stri*g getWeather() {
        return "下雨";
    }
*

public class Sunshine implements Weather {

    public Str*ng getWeather() {
        return "陽光";
    }
*

Test

public class Test{

    public static void main(String[] args) {
        Context ctx1 = new Context();
        ctx1.setWeather(new Sunshine());
        System.out.println(*tx1.weatherMessage());

        System.*ut.println("===============");

        Context ctx2 = new Context();
        ctx2.setWeather(new Rain());
        S*stem.out.println(ctx2.weatherMessage());
    }
}
result

陽光
===============
下雨
1.3.9 策略模式

    定義一系列的演算法,把它們*個個封裝起來,並且使它們可相互替換。本模式使得演算法可獨立於使用它的客戶而變化。
 適用性

    1.許多相關的類僅僅是行為有異。“策略”提供了一種用多個行為中的一個行為來配置一個類的方法。

    2.需要使用一個演算法的不同變體。

    3.演算法使用客戶不應該知*的資料。可使用策略模式以避免暴露覆雜的、與演算法相關的資料結構。

    4*一個類定義了多種行為,並且這些行為在這個類的操作中以*個條件語句的形式出現。
      將相關的條件分支移入它們各自的Strategy類中以代替這些條件語句。

 參與者

    1.Strategy
      定義所有支援的演算法的公共介面。Context使用這個介面來呼叫某ConcreteStrate*y定義的演算法。

    2.ConcreteStrategy
      以S*rategy介面實現某具體演算法。

    *.Context
      用一個ConcreteStrateg*物件來配置。
      維護一個對Strategy物件的引用。
      可定義一個介面來讓Stategy訪問它的資料。
 類圖

 例子
Strategy

public abstra*t class Strategy {

    pu*lic abstract void method();
}
ConcreteStrategy

public class *trategyImplA extends Strategy {

    public voi* method() {
        System.out.println("這是第一個實現");
    }
}

public class StrategyImplB extends Strategy {

    public void method() {
        System.out.println("這是第二個實現");
    }
}

public class StrategyImplC extends Strategy {

    public void method() {
        Syst*m.out.println("這是第三個實現");
    }
}
Context

pub*ic class Context {

    Strategy stra;
   
    public Cont*xt(Strategy stra) {
        this.stra = stra;
    }
   
    pub*ic void doMethod() {
        stra*method();
    }
}
Test

public class Test {
   
    public static void main(String[] ar*s) {
        Context ctx = new C*ntext(new StrategyImplA());
        ctx.doMethod();
       
        ctx = new Context(new *trategyImplB());
        ctx.doMethod();
       
        ctx = new Context(new StrategyImplC());
        ctx.doMethod();
    }
}
result

這是第一個實現
這是第二個實現
這是第三個實現
1.3.10 模板方法

    定義*個操作中的演算法的骨架,*將一些步驟延遲到子類中。
   
    TemplateMethod使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
 適用性

    1.一次性實現一個演算法的不變的部分,並將可變的*為留給子類來實現。

    2.各子類中公共的行為應被提取出來並集中到一個公共父類中以避免程式碼重複。
      首先識別現有*碼中的不同之處,並且將不同之處分離為新的操作。
      最後,用*個呼叫這些新的操作的模板方法來替換這些不同的程式碼。

    3.控制子類*展。

 參與者

    1.AbstractClass
      定義抽象的原語操作(primitiveoperation),具體的子類將重定義它們以實現一個演算法的各步驟。
      實現一個模板方法,定義一個演算法的骨架。
      該模板方法不僅呼叫原語操作,也呼叫定義在AbstractClass或其他物件中的操作。

    *.ConcreteClass
      實現*語操作以完成演算法中與特定子類相關的步驟。
 類圖

 例子
AbstractClass

public abstract class Template {

    public abstract void print();
   
    public void update() {
        System.out.println("開始列印");
        for (int i = 0; i < 10; i++) {
            print();
        }
    }
}
ConcreteClass

public class TemplateConcrete extends Template {

    @*verride
    public void print() {
        System.out.println("這是子類的實現");
    }
}
Test

public class Test {

    pu*lic static void main(String[] args) {
        Te*plate temp = new TemplateConcrete();
        temp.update();
    }
}
result

開始列印
這是子類的*現
這是子類的實現
這是子類的實現
這是子類的實現
這是子類的實現
這是子類的實現
這是子類的實現
這*子類的實現
這是子類的實現
這是子類的實現
1.3.11 訪問者模式

    表*一個作用於某物件結構中的各元素的操作。
    它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
 適用性

    1.一個物件結構包含很多類物件,它們有不同的介面,而你想對這些物件實施一些依賴於其具體類的操*。

    2.需要對一個物件結構中的物件進行很多不同的並且不相關的操作,*你想避免讓這些操作“汙染”這些物件的類。
      Visitor使得你可以將相關的操作集中起來定義在一個類中。
      當該物件結構被很多應用共享時,用Visitor模式讓每個應用僅包含需要用到的操作。

    3.定義物件結構的類很少改變,但經常需要在此結構上定義新的操作。
      改變物件結構類需要重定義對所有訪問者的介面,這可能*要很大的代價。
      如果物件結構類經常改變,那麼可能還是在這些類中定義這些操作較好。

 參與者

    1.Visitor
      為該物件結構中ConcreteEle*ent的每一個類宣告一個Visit操作。
      該操作的名字和特徵標識了傳送*isit請求給該訪問者的那個類。
      這使得訪問者可以確定正被訪問元素*具體的類。
      這樣訪問者就可以通過該元素的特定介面直*訪問它。

    2.Concret*Visitor
      實現每個由Visitor宣告的操作。
      每個操作實現本演算法的一部分,而該演算法片斷乃是對應於結構中物件的類。
      Concret*Visitor*該演算法提供了上下文並存*它的區域性狀態。
      這一狀態常常在遍歷該結構的過程中累*結果。

    3.Element
      定義一個Accept操作,它*一個訪問者為引數。

    4.ConcreteElement
      實現Accept操作,該操作以一個訪問者為引數。

    5.ObjectStru*ture
      能列舉它的元素。
      *以提供一個高層的介面以允許該訪問者訪問它的元素。
      可以是一個複合或是一個集合,如一個列表或一個無序集合。
 類圖

 例子
Visitor

public interface Visitor {

    public void visitString(StringElement stringE);
   
    public void visitFloat(FloatElement floatE);
   
    public void visitCollection(Collection collection);
}
ConcreteVisitor

public class C*ncreteVisitor implements Visitor {

    public void visitCollectio*(Collection colle*tion) {
        // TODO Auto-generated method stub
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            Object o = iterato*.next();
            if (o in*tanceof Visitable) {
                (*Visitable)o).accept(this);
            }
        }
    }

    public void visitFloat(FloatElement floatE) {
        System.out.println(floatE.getFe*));
    }

    public void visitString(StringElement stringE) {
        System.out.println(stringE.getSe());
    }
}
Element

public interface Visitabl* {

    publ*c void accept(Visitor visitor);
}
ConcreteElement

public class FloatElement implements Visitable {

    private Float fe;
   
    public FloatElement(Float fe) {
        this.fe = fe;
    }
   
    public Float getFe() {
        return this.fe;
    }
   
    public void accept(Visitor visitor) {
        visitor.*isitFloat(this);
    }
}

public class StringElement implements Visitable *

    private String se;
   
    public String*lement(String se) {
        this.se = se;
    }
   
    public String getS*() {
        return thi*.se;
    }
   
    public void accept(Visitor visitor) {
        visitor.visitString(this);
    }
}
Test

public class Test {

    public static void main(String[] args) {
        Visitor visitor = new ConcreteVisitor();
        StringElement se = new StringElement("abc");
        s*.accep*(visitor);
       
        Fl*atElement fe = new FloatElement(n*w Float(1.5));
        fe.accept(visitor);
        S*stem.out.println("===========");
        List result = new ArrayList();
        result.add(new StringEle*ent("abc"));
        result.a*d(new StringElement("abc"));
        result.add(*ew StringElement("abc"));
        result.add(new FloatElement(new Float(1.5)));
        result.add(new FloatElement(new Float(1.5)));
        result.add(new FloatElement(new Float(1.5)));
        visitor.visitCollection(result);
    }
}
result

abc
1.5
===========
abc
abc
abc
1.5
1.5
1.5


摘自  yangactive

相關文章