23種java設計模式
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
相關文章
- 23種設計模式設計模式
- java23種設計模式——八、組合模式Java設計模式
- java23種設計模式——五、建造者模式Java設計模式
- java23種設計模式—— 二、單例模式Java設計模式單例
- java23種設計模式——三、工廠模式Java設計模式
- java23種設計模式——四、原型模式Java設計模式原型
- java中23種設計模式--原型模式(Portotype)Java設計模式原型
- java23種設計模式-門面模式(外觀模式)Java設計模式
- java23種設計模式——六、介面卡模式Java設計模式
- 23種設計模式(八)-原型設計模式設計模式原型
- 23種設計模式(二)---策略設計模式設計模式
- 23種設計模式(四)-代理模式設計模式
- GOF23--23種設計模式(一)Go設計模式
- Java23種設計模式【22】----》觀察者模式(Observer)Java設計模式Server
- 23種設計模式(七)-狀態設計模式設計模式
- 23種設計模式(四)- 模板方法設計模式設計模式
- 23種設計模式簡介設計模式
- 23種軟體設計模式設計模式
- 23種設計模式-原型模式(3)設計模式原型
- 【23種設計模式】外觀模式(十)設計模式
- 23種設計模式:03裝飾模式設計模式
- 23種設計模式之組合模式設計模式
- 23種設計模式(抽象工廠模式)設計模式抽象
- 【圖解設計模式系列】23句話總結23種設計模式圖解設計模式
- 23種設計模式(六)-責任鏈設計模式設計模式
- 23種設計模式之模板方法設計模式
- 畫江湖之23種設計模式設計模式
- 淺談23種設計模式之單例設計模式設計模式單例
- 23種設計模式(一)---簡單工廠設計模式設計模式
- 23種設計模式之介面卡模式設計模式
- 23種設計模式之直譯器模式設計模式
- 23種設計模式(三)--裝飾器模式設計模式
- 23種設計模式之——動態代理模式設計模式
- 重溫23種設計模式(11):原型模式設計模式原型
- 23種設計模式之代理模式(靜態代理)設計模式
- 實踐GoF的23種設計模式:命令模式Go設計模式
- 23種設計模式之抽象工廠設計模式抽象
- 圖文詳解23種設計模式設計模式
- 詳細講解23種設計模式設計模式