設計模式(Design pattern)是一套被重複使用、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。
設計模式分為三種類型,共23種:
參考Hongyang、菜鳥教學等處文章所寫。如有錯誤歡迎指正,如有侵權,請聯絡我刪除。
1. 設計模式觀察者模式(Observer Pattern) 以微信公眾服務為例
2. 設計模式工廠模式(Factory Pattern) 從賣肉夾饞說起
3. 設計模式單例設計模式(Singleton Pattern) 完全解析
4. 設計模式策略模式(Strategy Pattern) 以角色遊戲為背景
5. 設計模式轉接器模式(Adapter Pattern) 以手機充電器為例
6. 設計模式指令模式(Command Pattern) 管理智慧家電
7. 設計模式裝飾者模式(Decorator Pattern) 帶你重返傳奇世界
8. 設計模式外觀模式(Facade Pattern) 一鍵電影模式
9. 設計模式模版方法模式(Template Method Pattern) 展現程式設計師的一天
10. 設計模式狀態模式(State Pattern) 以自動販賣機為例
11. 設計模式建造者模式(Builder Pattern) 以造汽車買汽車為例
12. 設計模式原型模式(Prototype Pattern) 以取得多種形狀為例
13. 設計模式享元模式(Flyweight Pattern) 以隨機取得多種形狀為例
14. 設計模式代理模式(Proxy Pattern) 以取得磁碟中的圖片為例
15. 設計模式橋接模式(Bridge Pattern) 以畫不同顏色的圓為例
16. 設計模式組合模式(Composite Pattern) 以建立和列印員工的層次結構為例
17. 設計模式迭代器模式(Iterator Pattern) 以使用迭代器列印名字為例
18. 設計模式中介者模式(Mediator Pattern) 以公共聊天室為例
19. 設計模式備忘錄模式(Memento Pattern) 以使用備忘錄為例
20. 設計模式解譯器模式(Interpreter Pattern) 以解釋一句話為例
21. 設計模式責任鏈模式(Chain of Responsibility Pattern) 以Android Studio中列印日誌為例
22. 設計模式訪客模式(Visitor Pattern) 以顯示電腦的組成部分為例
- Observer
- Factory
- Singleton
- Strategy
- Adapter
- Command
- Decorator
- Facade
- Template Method
- State
- Builder
- Prototype
- Flyweight
- Proxy
- Bridge
- Composite
- Iterator
- Mediator
- Memento
- Chain of Responsibility
- Visitor
定義了物件之間的一對多的依賴,這樣一來,當一個物件改變時,它的所有的依賴者都會收到通知並自動更新。
對於JDK或Andorid中都有很多地方實現了觀察者模式,例如XXXView.addXXXListenter , 當然了XXXView.setOnXXXListener不一定是觀察者模式,因為觀察者模式是一種一對多的關係,對於setXXXListener是1對1的關係,應該叫回調。
專題介面:Subject.java ;
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
3D服務號的實作類別:ObjectFor3D.java
@ Override
public void registerObserver ( Observer observer ) {
observers . add ( observer );
}
@ Override
public void removeObserver ( Observer observer ) {
int index = observers . indexOf ( observer );
if ( index >= 0 ) {
observers . remove ( index );
}
}
@ Override
public void notifyObservers () {
for ( Observer observer : observers ) {
observer . update ( msg );
}
}
/**
* 主题更新信息
*/
public void setMsg ( String msg ) {
this . msg = msg ;
notifyObservers ();
}
所有觀察者需要實作此介面:Observer.java
public ObserverUser1 ( Subject subject ) {
subject . registerObserver ( this );
}
@ Override
public void update ( String msg ) {
Log . e ( "-----ObserverUser1 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
最後測試:ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
簡單列一下這個模式的家族:
1.靜態工廠模式
2.簡單工廠模式(店裡買肉夾饃)
public RoujiaMo creatRoujiaMo ( String type ) {
RoujiaMo roujiaMo = null ;
switch ( type ) {
case "Suan" :
roujiaMo = new ZSuanRoujiaMo ();
break ;
case "La" :
roujiaMo = new ZLaRoujiaMo ();
break ;
case "Tian" :
roujiaMo = new ZTianRoujiaMo ();
break ;
default : // 默认为酸肉夹馍
roujiaMo = new ZSuanRoujiaMo ();
break ;
}
return roujiaMo ;
}
3.工廠方法模式(開分店)
提供創建肉夾饃店抽象方法:RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
具體實作抽象方法:XianRoujiaMoStore.java
分店依舊使用簡單工廠模式:XianSimpleRoujiaMoFactory.java
4.抽象工廠模式(使用官方提供的原料)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
單例模式主要是為了避免因為創建了多個實例造成資源的浪費,且多個實例由於多次呼叫容易導致結果出現錯誤,而使用單例模式能夠保證整個應用中有且只有一個實例。
定義:只需要三步驟就可以保證物件的唯一性
對比定義:
餓漢式[可用]:SingletonEHan.java
含懶漢式[雙重校驗鎖推薦用]:SingletonLanHan.java
private SingletonLanHan () {}
private static SingletonLanHan singletonLanHanFour ;
public static SingletonLanHan getSingletonLanHanFour () {
if ( singletonLanHanFour == null ) {
synchronized ( SingletonLanHan . class ) {
if ( singletonLanHanFour == null ) {
singletonLanHanFour = new SingletonLanHan ();
}
}
}
return singletonLanHanFour ;
}
策略模式:定義了演算法族,分別封裝起來,讓它們之間可相互替換,此模式讓演算法的變化獨立於使用演算法的客戶。
RoleA roleA = new RoleA ( "---A" );
roleA . setiDisplayBehavior ( new DisplayYZ ())
. setiAttackBehavior ( new AttackXL ())
. setiDefendBehavior ( new DefendTMS ())
. setiRunBehavior ( new RunJCTQ ());
roleA . display (); // 样子
roleA . attack (); // 攻击
roleA . run (); // 逃跑
roleA . defend (); // 防御
定義:將一個類別的接口轉換成客戶期望的另一個接口,適配器讓原本接口不相容的類別可以相互合作。這個定義還好,說適配器的功能就是把一個介面轉成另一個介面。
以充電器為實例: 手機充電器通常都是5V左右吧,咱天朝的家用交流電壓220V,所以手機充電需要一個轉接器(降壓器)
一部手機: Mobile.java
手機依賴一個提供5V電壓的介面: V5Power.java
我們擁有的是220V家用交流電: V220Power.java
適配器,完成220V轉5V的作用:V5PowerAdapter.java
最後測試:給手機一個電:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
定義:將「請求」封裝成對象,以便使用不同的請求、佇列或日誌來參數化其他對象。命令模式也支援可撤銷的操作。 (簡化: 將請求封裝成對象,將動作請求者和動作執行者解耦。)
QuickCommand quickCloseCommand = new QuickCommand ( new Command []{ new LightOffCommand ( light ), new ComputerOffCommand ( computer ), new DoorCloseCommand ( door )});
controlPanel . setCommands ( 6 , quickOpenCommand );
controlPanel . keyPressed ( 6 );
controlPanel . setCommands ( 0 , new DoorOpenCommand ( door )); // 开门
controlPanel . keyPressed ( 0 );
裝飾者模式:若要擴展功能,裝飾者提供了比整合更有彈性的替代方案,動態地將責任附加到物件上。
先簡單描述下裝飾者模式發揮作用的地方,當我們設計好了一個類,我們需要給這個類添加一些輔助的功能,並且不希望改變這個類的代碼,這時候就是裝飾者模式大展雄威的時候了。這裡也體現了一個原則:類別應該對擴展開放,對修改關閉。
需求:設計遊戲的裝備系統,基本要求,要可以計算出每種裝備在鑲嵌了各種寶石後的攻擊力和描述:
1、裝備的超類別:IEquip.java
2、各裝備的實作類:
3.裝飾品的超類(裝飾品也屬於裝備):IEquipDecorator.java
4、裝飾品的實作類:
5、最後測試:計算攻擊力和檢視描述:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
定義:提供一個統一的接口,用來存取子系統中的一群接口,外觀定義了一個高層的接口,讓子系統更容易使用。其實就是為了方便客戶的使用,把一群操作,封裝成一個方法。
需求:我比較喜歡看電影,於是買了投影機、電腦、音響、設計了房間的燈光、買了爆米花機,然後我想看電影的時候,我需要一鍵觀影和一鍵關閉。
每個設備類別的開關等操作:
eg: 爆米花機:PopcornPopper.java
電影院類:HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
最後測試:一鍵觀影:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
定義:定義了一個演算法的骨架,而將一些步驟延遲到子類別中,模版方法使得子類別可以在不改變演算法結構的情況下,重新定義演算法的步驟。
需求:簡單描述一下:本公司有程式猿、測試、HR、專案經理等人,以下使用模版方法模式,記錄所有人員的上班狀況
模板方法模式中的三類角色
1.具體方法(Concrete Method)
2、抽象方法(Abstract Method)
3.鉤子方法(Hook Method)
工人的超類別:Worker.java
// 具体方法
public final void workOneDay () {
Log . e ( "workOneDay" , "-----------------work start----------------" );
enterCompany ();
work ();
exitCompany ();
Log . e ( "workOneDay" , "-----------------work end----------------" );
}
// 工作 抽象方法
public abstract void work ();
// 钩子方法
public boolean isNeedPrintDate () {
return false ;
}
private void exitCompany () {
if ( isNeedPrintDate ()) {
Log . e ( "exitCompany" , "---" + new Date (). toLocaleString () + "--->" );
}
Log . e ( "exitCompany" , name + "---离开公司" );
}
程式設計師實作類別(可得知時間):ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
最後測試:
查看所有人員的工作:
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
查看程序猿離開公司的時間:
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
定義:允許物件在內部狀態改變時改變它的行為,而物件看起來好像修改了它的類別。
定義又開始模糊了,理一下,當物件的內部狀態改變時,它的行為跟隨狀態的改變而改變了,看起來好像重新初始化了一個類似的。
需求:以自動販賣機為例(有已投幣、未投幣等狀態及投幣、退幣等方法)
最初實現待改進的售貨機:VendingMachine.java
改良後的販賣機(更具延展性):VendingMachineBetter.java
// 放钱
public void insertMoney () {
currentState . insertMoney ();
}
// 退钱
public void backMoney () {
currentState . backMoney ();
}
// 转动曲柄
public void turnCrank () {
currentState . turnCrank ();
if ( currentState == soldState || currentState == winnerState ) {
currentState . dispense (); //两种情况会出货
}
}
// 出商品
public void dispense () {
Log . e ( "VendingMachineBetter" , "---发出一件商品" );
if ( count > 0 ) {
count --;
}
}
// 设置对应状态
public void setState ( State state ) {
this . currentState = state ;
}
狀態的介面:State.java
對應狀態的介面實作類別:
改進後的售貨機測試:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
建造模式是物件的創建模式。建造模式可以將一個產品的內部表象(internal representation)與產品的生產過程分割開來,從而可以使一個建造過程產生具有不同的內部表象的產品對象。
需求:使用者去汽車店購買汽車。
分析:汽車店根據每位使用者的需求提取對應汽車
建造者超類別:Builder
public abstract class Builder {
public abstract void setPart ( String name , String type );
public abstract Product getProduct ();
}
建造者對應實作類別:ConcreteBuilder
public class ConcreteBuilder extends Builder {
private Product product = new Product ();
@ Override
public void setPart ( String name , String type ) {
product . setName ( name );
product . setType ( type );
}
@ Override
public Product getProduct () {
return product ;
}
}
店長Director取汽車:
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
原型模式是用於創建重複的對象,同時又能確保性能。這種類型的設計模式屬於創建型模式,它提供了一種創建物件的最佳方式。
這種模式是實作了一個原型接口,該接口用於創建當前物件的克隆。當直接建立物件的代價比較大時,則採用這種模式。例如,一個物件需要在一個高代價的資料庫操作之後被建立。我們可以快取該對象,在下一個請求時返回它的克隆,在需要的時候更新資料庫,以此來減少資料庫呼叫。
以獲取多種形狀為例,共分四步:
1.創建一個實作了Cloneable 介面的抽象類別。 Shape(implements Cloneable)
public abstract class Shape implements Cloneable {
private String id ;
protected String type ;
public abstract void draw ();
public String getId () {
return id ;
}
public void setId ( String id ) {
this . id = id ;
}
@ Override
public Object clone () {
Object object = null ;
try {
object = super . clone ();
} catch ( CloneNotSupportedException e ) {
Log . e ( "--" , e . getMessage ());
}
return object ;
}
}
2.創建擴展了上面抽象類別的實體類別。 Circle、Rectangle、Square
public class Circle extends Shape {
public Circle () {
type = "Circle" ;
}
@ Override
public void draw () {
Log . e ( "---" , "Inside Circle::draw() method." );
}
}
3.建立一個類,從資料庫取得實體類,並把它們儲存在一個Hashtable 中。 ShapeCache
public class ShapeCache {
private static Hashtable < String , Shape > shapeMap = new Hashtable < String , Shape >();
public static Shape getShape ( String shapeId ) {
Shape shapeCache = shapeMap . get ( shapeId );
return ( Shape ) shapeCache . clone ();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
public static void loadCache () {
Circle circle = new Circle ();
circle . setId ( "1" );
shapeMap . put ( circle . getId (), circle );
Rectangle rectangle = new Rectangle ();
rectangle . setId ( "2" );
shapeMap . put ( rectangle . getId (), rectangle );
Square square = new Square ();
square . setId ( "3" );
shapeMap . put ( square . getId (), square );
}
}
4.使用ShapeCache 類別來取得儲存在Hashtable 中的形狀的克隆。
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
主要用於減少創建物件的數量,以減少記憶體佔用和提高效能。這種類型的設計模式屬於結構型模式,它提供了減少物件數量從而改善應用所需的物件結構的方式。
享元模式嘗試重複使用現有的同類對象,如果未找到匹配的對象,則建立新對象。我們將透過建立5 個物件來畫出20 個分佈於不同位置的圓來示範這種模式。由於只有5 種可用的顏色,所以color 屬性被用來檢查現有的Circle 物件。
以隨機取得多種形狀為例,共分四步:
1、創建一個介面。
public interface Shape {
void draw ();
}
2、建立實作介面的實體類別。
public class Circle implements Shape {
private String color ;
private int x ;
private int y ;
private int radius ;
public Circle ( String color ) {
this . color = color ;
}
public void setX ( int x ) {
this . x = x ;
}
public void setY ( int y ) {
this . y = y ;
}
public void setRadius ( int radius ) {
this . radius = radius ;
}
@ Override
public void draw () {
Log . e ( "---" , "Circle: Draw() [Color : " + color
+ ", x : " + x + ", y :" + y + ", radius :" + radius );
}
}
3.創建一個工廠,產生基於給定資訊的實體類別的物件。
public class ShapeFactory {
private static final HashMap < String , Shape > circleMap = new HashMap < String , Shape >();
public static Shape getShape ( String color ) {
Shape shape = circleMap . get ( color );
if ( shape == null ) {
shape = new Circle ( color );
circleMap . put ( color , shape );
Log . e ( "getShape" , "Creating circle of color : " + color );
}
return shape ;
}
}
4、使用該工廠,透過傳遞顏色資訊來取得實體類別的物件。
for ( int i = 0 ; i < 20 ; i ++) {
Circle circle = ( Circle ) ShapeFactory . getShape ( getRandomColor ());
circle . setX ( getRandomX ());
circle . setY ( getRandomY ());
circle . setRadius ( 100 );
circle . draw ();
}
一個類別代表另一個類別的功能。在代理模式中,我們建立具有現有對象的對象,以便向外界提供功能介面。可以理解為記憶體中沒有這個物件就創建,有就直接回傳這個物件。
以取得磁碟中的圖片為例,總共分三步驟:
1、創建一個介面。
public interface Image {
void display ();
}
2、建立實作介面的實體類別RealImage。對應代理類別:ProxyImage。
public class RealImage implements Image {
private String fileName ;
public RealImage ( String fileName ) {
this . fileName = fileName ;
loadFromDisk ( fileName );
}
private void loadFromDisk ( String fileName ) {
Log . e ( "RealImage" , "loading " + fileName );
}
@ Override
public void display () {
Log . e ( "RealImage" , "Displaying " + fileName );
}
}
public class ProxyImage implements Image {
private String fileName ;
private RealImage realImage ;
public ProxyImage ( String fileName ) {
this . fileName = fileName ;
}
@ Override
public void display () {
if ( realImage == null ) {
realImage = new RealImage ( fileName );
}
realImage . display ();
}
}
3.當被要求時,使用ProxyImage 來取得RealImage 類別的物件。
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
橋接(Bridge)是用來把抽象化與實作化解耦,使得二者可以獨立變化。這種類型的設計模式屬於結構型模式,它透過提供抽象化和實現化之間的橋接結構,來實現二者的解耦。
以畫不同顏色的圓為例,實現共分五步:
1、創建橋接實現介面。
public interface DrawAPI {
void drawCircle ( int radius , int x , int y );
}
2.創建實作了DrawAPI 介面的實體橋接實作類別。 RedCircle、GreenCircle
public class RedCircle implements DrawAPI {
@ Override
public void drawCircle ( int radius , int x , int y ) {
Log . e ( "---" , "Drawing Circle[ color: red, radius: "
+ radius + ", x: " + x + ", " + y + "]" );
}
}
3.使用DrawAPI 介面建立抽象類別Shape。
public abstract class Shape {
protected DrawAPI drawAPI ;
protected Shape ( DrawAPI drawAPI ) {
this . drawAPI = drawAPI ;
}
public abstract void draw ();
}
4.創建實作了Shape 介面的實體類別。
public class Circle extends Shape {
private int x , y , radius ;
protected Circle ( int x , int y , int radius , DrawAPI drawAPI ) {
super ( drawAPI );
this . x = x ;
this . y = y ;
this . radius = radius ;
}
@ Override
public void draw () {
drawAPI . drawCircle ( radius , x , y );
}
}
5.使用Shape 和DrawAPI 類別畫出不同顏色的圓。
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
又叫部分整體模式,是用來把一組相似的物件當作一個單一的物件。組合模式依據樹狀結構來組合對象,用來表示部分以及整體層次。這種類型的設計模式屬於結構型模式,它創建了物件群組的樹狀結構。
以建立和列印員工的層次結構為例,最小單元範例:
1、建立Employee 類,該類別帶有Employee 物件的列表。
public class Employee {
private String name ;
// 部门
private String dept ;
// 工资
private int salary ;
// 员工 list
private List < Employee > subordinates ;
public Employee ( String name , String dept , int salary ) {
this . name = name ;
this . dept = dept ;
this . salary = salary ;
this . subordinates = new ArrayList < Employee >();
}
public void add ( Employee e ) {
subordinates . add ( e );
}
public void remove ( Employee e ) {
subordinates . remove ( e );
}
public List < Employee > getSubordinates () {
return subordinates ;
}
@ Override
public String toString () {
return "Employee{" +
"name='" + name + ''' +
", dept='" + dept + ''' +
", salary=" + salary +
", subordinates=" + subordinates +
'}' ;
}
}
2.使用Employee 類別來建立和列印員工的層次結構。
final Employee ceo = new Employee ( "John" , "CEO" , 30000 );
Employee headSales = new Employee ( "Robert" , "Head sales" , 20000 );
Employee headMarketing = new Employee ( "Michel" , "Head Marketing" , 20000 );
Employee clerk1 = new Employee ( "Laura" , "Marketing" , 10000 );
Employee clerk2 = new Employee ( "Bob" , "Marketing" , 10000 );
Employee salesExecutive1 = new Employee ( "Richard" , "Sales" , 10000 );
Employee salesExecutive2 = new Employee ( "Rob" , "Sales" , 10000 );
ceo . add ( headSales );
ceo . add ( headMarketing );
headSales . add ( salesExecutive1 );
headSales . add ( salesExecutive2 );
headMarketing . add ( clerk1 );
headMarketing . add ( clerk2 );
Log . e ( "---" , ceo . toString ());
// 打印
/*
* Employee{name='John', dept='CEO', salary=30000,
* subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
* subordinates=[
* Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
* Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
* Employee{name='Michel', dept='Head Marketing', salary=20000,
* subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
* Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
*/
Java 和.Net 程式設計環境中非常常用的設計模式。這種模式用於順序存取集合物件的元素,不需要知道集合物件的底層表示。迭代器模式屬於行為型模式。
以使用迭代器印出名字為例,總共分三步驟:
1、建立介面:
public interface Iterator {
public boolean hasNext ();
public Object next ();
}
public interface Container {
public Iterator getIterator ();
}
2.創建實作了Container 介面的實體類別。類別有實作了Iterator 介面的內部類別NameIterator。
public class NameRepository implements Container {
private String names [] = { "John" , "jingbin" , "youlookwhat" , "lookthis" };
@ Override
public Iterator getIterator () {
return new NameIterator ();
}
private class NameIterator implements Iterator {
int index ;
@ Override
public boolean hasNext () {
if ( index < names . length ) {
return true ;
}
return false ;
}
@ Override
public Object next () {
if ( hasNext ()) {
return names [ index ++];
}
return null ;
}
}
}
3.使用NameRepository 取得迭代器,並列印名字。
NameRepository nameRepository = new NameRepository ();
for ( Iterator iterator = nameRepository . getIterator (); iterator . hasNext (); ) {
String name = ( String ) iterator . next ();
Log . e ( "---" , name );
/*
* /---: John
* /---: jingbin
* /---: youlookwhat
* /---: lookthis
*/
}
用來降低多個物件和類別之間的通訊複雜性。這種模式提供了一個中介類,通常處理不同類別之間的通信,並支援鬆散耦合,使程式碼易於維護。中介者模式屬於行為型模式。
以公共聊天室為例,最小單元範例步驟:
1、創建中介類。
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2、建立user 類別。
public class User {
private String name ;
public User ( String name ) {
this . name = name ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public void sendMessage ( String message ) {
// 使用中介类
CharRoom . showMessage ( this , message );
}
}
3、使用User 物件來顯示他們之間的通訊。
User jingbin = new User ( "jingbin" );
jingbin . sendMessage ( "Hi~ youlookwhat!" );
//---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
User jingbin = new User ( "youlookwhat" );
jingbin . sendMessage ( "Hi~ jingbin!" );
//---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
保存一個物件的某個狀態,以便在適當的時候恢復物件。備忘錄模式屬於行為型模式。
以使用備忘錄為例,最小單元步驟:
1、建立備忘錄Memento 類別。
public class Memento {
private String state ;
public Memento ( String state ) {
this . state = state ;
}
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
}
2、創建Originator 類別。
public class Originator {
private String state ;
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
public Memento setSateToMemento () {
return new Memento ( state );
}
public String getStateFromMemento ( Memento memento ) {
return memento . getState ();
}
}
3.創建CareTaker 類別。
public class CareTaker {
private List < Memento > mementoList = new ArrayList < Memento >();
public void add ( Memento memento ) {
mementoList . add ( memento );
}
public Memento get ( int index ) {
return mementoList . get ( index );
}
}
4、使用CareTaker 和Originator 物件。
// 管理者
CareTaker careTaker = new CareTaker ();
Originator originator = new Originator ();
originator . setState ( "State #1" );
originator . setState ( "State #2" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #3" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #4" );
Log . e ( "---" , "Current State: " + originator . getState ());
// 得到保存的状态
String fromMemento1 = originator . getStateFromMemento ( careTaker . get ( 0 ));
Log . e ( "---" , "First Saved State: " + fromMemento1 );
String fromMemento2 = originator . getStateFromMemento ( careTaker . get ( 1 ));
Log . e ( "---" , "Second Saved State: " + fromMemento2 );
/*
* /---: Current State: State #4
* /---: First Saved State: State #2
* /---: Second Saved State: State #3
*/
提供了評估語言的語法或表達式的方式,它屬於行為型模式。這種模式實現了一個表達式接口,該接口解釋一個特定的上下文。這種模式被用在SQL 解析、符號處理引擎等。
以解釋一句話為例,最小單元步驟:
1、建立一個表達式介面Expression。
public interface Expression {
public boolean interpreter ( String content );
}
2、創建實現了上述介面的實體類別。 TerminalExpression、OrExpression、AndExpression。
public class TerminalExpression implements Expression {
private String data ;
public TerminalExpression ( String data ) {
this . data = data ;
}
@ Override
public boolean interpreter ( String content ) {
// 是包含判断
return content . contains ( data );
}
}
public class OrExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public OrExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) || expression2 . interpreter ( content );
}
}
public class AndExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public AndExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) && expression2 . interpreter ( content );
}
}
3.使用Expression 類別來建立規則,並解析它們。
/**
* 规则:jingbin 和 youlookwhat 是男性
*/
public static Expression getMaleExpression () {
TerminalExpression jingbin = new TerminalExpression ( "jingbin" );
TerminalExpression youlookwhat = new TerminalExpression ( "youlookwhat" );
return new OrExpression ( jingbin , youlookwhat );
}
/**
* 规则:Julie 是一个已婚的女性
*/
public static Expression getMarriedWomanExpression () {
TerminalExpression julie = new TerminalExpression ( "Julie" );
TerminalExpression married = new TerminalExpression ( "Married" );
return new AndExpression ( julie , married );
}
Expression maleExpression = getMaleExpression ();
// jingbin is male: true
Log . e ( "---" , "jingbin is male: " + maleExpression . interpreter ( "jingbin" ));
Expression womanExpression = getMarriedWomanExpression ();
// Julie is married woman: true
Log . e ( "---" , "Julie is married woman: " + womanExpression . interpreter ( "Married Julie" ));
責任鏈模式(Chain of Responsibility Pattern)為請求創建了一個接收者物件的鏈。這種模式給予請求的類型,對請求的發送者和接收者進行解耦。這種類型的設計模式屬於行為型模式。在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個物件不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。
以Android Studio中列印日誌為例,最小單元步驟:
1、建立抽象的記錄器類別AbstractLogger。
public abstract class AbstractLogger {
public static int INFO = 1 ;
public static int DEBUG = 2 ;
public static int ERROR = 3 ;
protected int level ;
// 责任链中的下一个元素
protected AbstractLogger nextLogger ;
public void setNextLogger ( AbstractLogger nextLogger ) {
this . nextLogger = nextLogger ;
}
public void logMessage ( int level , String message ) {
if ( this . level <= level ) {
write ( message );
}
// 递归效果,不断调用下一级 logMessage
if ( nextLogger != null ) {
nextLogger . logMessage ( level , message );
}
}
protected abstract void write ( String message );
}
2、建立擴展了該記錄器類別的實體類別。
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Standard Console::Logger " + message );
}
}
public class FileLogger extends AbstractLogger {
public FileLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "File::Logger " + message );
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Error Console::Logger " + message );
}
}
3、建立不同類型的記錄器。賦予它們不同的錯誤級別,並在每個記錄器中設定下一個記錄器。每個記錄器中的下一個記錄器代表的是鏈的一部分。
public static AbstractLogger getChainOfLoggers () {
ErrorLogger errorLogger = new ErrorLogger ( AbstractLogger . ERROR );
FileLogger fileLogger = new FileLogger ( AbstractLogger . DEBUG );
ConsoleLogger consoleLogger = new ConsoleLogger ( AbstractLogger . INFO );
errorLogger . setNextLogger ( fileLogger );
fileLogger . setNextLogger ( consoleLogger );
return errorLogger ;
}
AbstractLogger logger = getChainOfLoggers ();
// ---: Standard Console::Logger this is an information.
logger . logMessage ( AbstractLogger . INFO , "this is an information." );
// ---: File::Logger this is a debug level information.
// ---: Standard Console::Logger this is a debug level information.
logger . logMessage ( AbstractLogger . DEBUG , "this is a debug level information." );
// ---: Error Console::Logger this is a error level information.
// ---: File::Logger this is a error level information.
// ---: Standard Console::Logger this is a error level information.
logger . logMessage ( AbstractLogger . ERROR , "this is a error level information." );
在訪客模式中,我們使用了一個訪客類,它改變了元素類的執行演算法。透過這種方式,元素的執行演算法可以隨著訪客改變而改變。這種類型的設計模式屬於行為型模式。根據模式,元素對像已接受訪問者對象,這樣訪問者對象就可以處理元素對像上的操作。
以顯示計算機的組成部分為例,主要分五步驟實現:
1、定義一個表示元素的介面。
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2、創建擴展了上述類別的實體類別。 Keyboard、Monitor、Mouse、Computer
public class Computer implements ComputerPart {
private ComputerPart [] parts ;
public Computer () {
this . parts = new ComputerPart []{ new Mouse (), new Keyboard (), new Monitor ()};
}
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
for ( ComputerPart part : parts ) {
part . accept ( computerPartVisitor );
}
computerPartVisitor . visit ( this );
}
}
public class Mouse implements ComputerPart {
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
computerPartVisitor . visit ( this );
}
}
3、定義一個表示訪客的介面。
public interface ComputerPartVisitor {
public void visit ( Computer computer );
public void visit ( Mouse mouse );
public void visit ( Keyboard keyboard );
public void visit ( Monitor monitor );
}
4.創建實現了上述類別的實體訪客。
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@ Override
public void visit ( Computer computer ) {
Log . e ( "---" , "Displaying Computer." );
}
@ Override
public void visit ( Mouse mouse ) {
Log . e ( "---" , "Displaying Mouse." );
}
@ Override
public void visit ( Keyboard keyboard ) {
Log . e ( "---" , "Displaying Keyboard." );
}
@ Override
public void visit ( Monitor monitor ) {
Log . e ( "---" , "Displaying Monitor." );
}
}
5.使用ComputerPartDisplayVisitor 來顯示Computer 的組成部分。
ComputerPart computer = new Computer ();
computer . accept ( new ComputerPartDisplayVisitor ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/