Java設計模式 – JAVA編程語言程序開發技術文章

目錄
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對象的場景。
    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 責任鏈模式
    使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一*鏈,
    並*著這條鏈傳遞該請求,直到有一個對象處理它為止。
   
    這一模式的想法是,給多個對象處理一個請求的機會,從而解耦發送者和接受者.
 適用性www.aiwalls.com
    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 

摘自  huahuagongzi9999的專欄 

發佈留言