23種設(shè)計模式及要點

預(yù)警:本篇文章較長,建議先mark后看

1.單例模式(Singleton Pattern)

定義:Ensure a class has only one instance, and provide a global point of access
to it.(確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實
例。)
通用代碼:(是線程安全的)

public class Singleton {
 private static final Singleton singleton = new Singleton();
//限制產(chǎn)生多個對象
 private Singleton(){
 }
 //通過該方法獲得實例對象
 public static Singleton getSingleton(){
 return singleton;
 }
 //類中其他方法,盡量是 static
 public static void doSomething(){
 }
}

使用場景:
● 要求生成唯一序列號的環(huán)境;
● 在整個項目中需要一個共享訪問點或共享數(shù)據(jù),例如一個 Web 頁面上的計數(shù)
器,可以不用把每次刷新都記錄到數(shù)據(jù)庫中,使用單例模式保持計數(shù)器的值,并確
保是線程安全的;
● 創(chuàng)建一個對象需要消耗的資源過多,如要訪問 IO 和數(shù)據(jù)庫等資源;
● 需要定義大量的靜態(tài)常量和靜態(tài)方法(如工具類)的環(huán)境,可以采用單例模式
(當(dāng)然,也可以直接聲明為 static 的方式)。
線程不安全實例:

public class Singleton {
 private static Singleton singleton = null;
 //限制產(chǎn)生多個對象
 private Singleton(){
 }
 //通過該方法獲得實例對象
 public static Singleton getSingleton(){
 if(singleton == null){
 singleton = new Singleton();
 }
 return singleton;
 }
}

解決辦法:
在 getSingleton 方法前加 synchronized 關(guān)鍵字,也可以在 getSingleton 方法內(nèi)增
加 synchronized 來實現(xiàn)。最優(yōu)的辦法是如通用代碼那樣寫。

2.工廠模式

定義:Define an interface for creating an object,but let subclasses decide which
class to instantiate.Factory Method lets a class defer instantiation to subclasses.
(定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類
的實例化延遲到其子類。)
Product 為抽象產(chǎn)品類負(fù)責(zé)定義產(chǎn)品的共性,實現(xiàn)對事物最抽象的定義;
Creator 為抽象創(chuàng)建類,也就是抽象工廠,具體如何創(chuàng)建產(chǎn)品類是由具體的實現(xiàn)工
廠 ConcreteCreator 完成的。
具體工廠類代碼:

public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
 Product product=null;
 try {
 product =
(Product)Class.forName(c.getName()).newInstance();
 } catch (Exception e) {
 //異常處理
 }
 return (T)product;
 }
}

簡單工廠模式:
一個模塊僅需要一個工廠類,沒有必要把它產(chǎn)生出來,使用靜態(tài)的方法
多個工廠類:
每個人種(具體的產(chǎn)品類)都對應(yīng)了一個創(chuàng)建者,每個創(chuàng)建者獨立負(fù)責(zé)創(chuàng)建對應(yīng)的
產(chǎn)品對象,非常符合單一職責(zé)原則
代替單例模式:
單例模式的核心要求就是在內(nèi)存中只有一個對象,通過工廠方法模式也可以只在內(nèi)
存中生產(chǎn)一個對象
延遲初始化:
ProductFactory 負(fù)責(zé)產(chǎn)品類對象的創(chuàng)建工作,并且通過 prMap 變量產(chǎn)生一個緩
存,對需要再次被重用的對象保留
使用場景:jdbc 連接數(shù)據(jù)庫,硬件訪問,降低對象的產(chǎn)生和銷毀

3.抽象工廠模式(Abstract Factory

Pattern)
定義:Provide an interface for creating families of related or dependent objects
without specifying their concrete classes.(為創(chuàng)建一組相關(guān)或相互依賴的對象提供
一個接口,而且無須指定它們的具體類。)
抽象工廠模式通用類圖:
抽象工廠模式通用源碼類圖:
抽象工廠類代碼:

public abstract class AbstractCreator {
 //創(chuàng)建 A 產(chǎn)品家族
 public abstract AbstractProductA createProductA();
 //創(chuàng)建 B 產(chǎn)品家族
 public abstract AbstractProductB createProductB();
}

使用場景:
一個對象族(或是一組沒有任何關(guān)系的對象)都有相同的約束。
涉及不同操作系統(tǒng)的時候,都可以考慮使用抽象工廠模式

4.模板方法模式(Template Method

Pattern)
定義:Define the skeleton of an algorithm in an operation,deferring some steps to
subclasses.Template Method lets subclasses redefine certain steps of an
algorithm without changing the algorithm's structure.(定義一個操作中的算法的框
架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義
該算法的某些特定步驟。)
AbstractClass 叫做抽象模板,它的方法分為兩類:
● 基本方法
基本方法也叫做基本操作,是由子類實現(xiàn)的方法,并且在模板方法被調(diào)用。
● 模板方法
可以有一個或幾個,一般是一個具體方法,也就是一個框架,實現(xiàn)對基本方法的調(diào)
度,完成固定的邏輯。
注意: 為了防止惡意的操作,一般模板方法都加上 final 關(guān)鍵字,不允許被覆
寫。
具體模板:ConcreteClass1 和 ConcreteClass2 屬于具體模板,實現(xiàn)父類所定義的
一個或多個抽象方法,也就是父類定義的基本方法在子類中得以實現(xiàn)
使用場景:
● 多個子類有公有的方法,并且邏輯基本相同時。
● 重要、復(fù)雜的算法,可以把核心算法設(shè)計為模板方法,周邊的相關(guān)細(xì)節(jié)功能則由
各個子類實現(xiàn)。
● 重構(gòu)時,模板方法模式是一個經(jīng)常使用的模式,把相同的代碼抽取到父類中,然
后通過鉤子函數(shù)(見“模板方法模式的擴展”)約束其行為。

5.建造者模式(Builder Pattern)

定義:Separate the construction of a complex object from its representation so
that the same construction process can create different representations.(將一個
復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。)
● Product 產(chǎn)品類
通常是實現(xiàn)了模板方法模式,也就是有模板方法和基本方法,例子中的
BenzModel 和 BMWModel 就屬于產(chǎn)品類。
● Builder 抽象建造者
規(guī)范產(chǎn)品的組建,一般是由子類實現(xiàn)。例子中的 CarBuilder 就屬于抽象建造者。
● ConcreteBuilder 具體建造者
實現(xiàn)抽象類定義的所有方法,并且返回一個組建好的對象。例子中的 BenzBuilder
和 BMWBuilder 就屬于具體建造者。
● Director 導(dǎo)演類
負(fù)責(zé)安排已有模塊的順序,然后告訴 Builder 開始建造
使用場景:
● 相同的方法,不同的執(zhí)行順序,產(chǎn)生不同的事件結(jié)果時,可以采用建造者模式。
● 多個部件或零件,都可以裝配到一個對象中,但是產(chǎn)生的運行結(jié)果又不相同時,
則可以使用該模式。
● 產(chǎn)品類非常復(fù)雜,或者產(chǎn)品類中的調(diào)用順序不同產(chǎn)生了不同的效能,這個時候使
用建造者模式非常合適。
建造者模式與工廠模式的不同:
建造者模式最主要的功能是基本方法的調(diào)用順序安排,這些基本方法已經(jīng)實現(xiàn)了,
順序不同產(chǎn)生的對象也不同;
工廠方法則重點是創(chuàng)建,創(chuàng)建零件是它的主要職責(zé),組裝順序則不是它關(guān)心的。

6.代理模式(Proxy Pattern)

定義:Provide a surrogate or placeholder for another object to control access to it.
(為其他對象提供一種代理以控制對這個對象的訪問。)
● Subject 抽象主題角色
抽象主題類可以是抽象類也可以是接口,是一個最普通的業(yè)務(wù)類型定義,無特殊要
求。
● RealSubject 具體主題角色
也叫做被委托角色、被代理角色。它才是冤大頭,是業(yè)務(wù)邏輯的具體執(zhí)行者。
● Proxy 代理主題角色
也叫做委托類、代理類。它負(fù)責(zé)對真實角色的應(yīng)用,把所有抽象主題類定義的方法
限制委托給真實主題角色實現(xiàn),并且在真實主題角色處理完畢前后做預(yù)處理和善后
處理工作。
普通代理和強制代理:
普通代理就是我們要知道代理的存在,也就是類似的 GamePlayerProxy 這個類的
存在,然后才能訪問;
強制代理則是調(diào)用者直接調(diào)用真實角色,而不用關(guān)心代理是否存在,其代理的產(chǎn)生
是由真實角色決定的。
普通代理:
在該模式下,調(diào)用者只知代理而不用知道真實的角色是誰,屏蔽了真實角色的變更
對高層模塊的影響,真實的主題角色想怎么修改就怎么修改,對高層次的模塊沒有
任何的影響,只要你實現(xiàn)了接口所對應(yīng)的方法,該模式非常適合對擴展性要求較高
的場合。
強制代理:
強制代理的概念就是要從真實角色查找到代理角色,不允許直接訪問真實角色。高
層模塊只要調(diào)用 getProxy 就可以訪問真實角色的所有方法,它根本就不需要產(chǎn)生
一個代理出來,代理的管理已經(jīng)由真實角色自己完成。
動態(tài)代理:
根據(jù)被代理的接口生成所有的方法,也就是說給定一個接口,動態(tài)代理會宣稱“我
已經(jīng)實現(xiàn)該接口下的所有方法了”。
兩條獨立發(fā)展的線路。動態(tài)代理實現(xiàn)代理的職責(zé),業(yè)務(wù)邏輯 Subject 實現(xiàn)相關(guān)的邏
輯功能,兩者之間沒有必然的相互耦合的關(guān)系。通知 Advice 從另一個切面切入,
最終在高層模塊也就是 Client 進(jìn)行耦合,完成邏輯的封裝任務(wù)。
動態(tài)代理調(diào)用過程示意圖:
動態(tài)代理的意圖:橫切面編程,在不改變我們已有代碼結(jié)構(gòu)的情況下增強或控制對
象的行為。
首要條件:被代理的類必須要實現(xiàn)一個接口。

7.原型模式(Prototype Pattern)

定義:Specify the kinds of objects to create using a prototypical instance,and
create new objects by copying this prototype.(用原型實例指定創(chuàng)建對象的種類,
并且通過拷貝這些原型創(chuàng)建新的對象。)
原型模式通用代碼:

public class PrototypeClass implements Cloneable{
 //覆寫父類 Object 方法
 @Override
 public PrototypeClass clone(){
 PrototypeClass prototypeClass = null;
 try {
 prototypeClass = (PrototypeClass)super.clone();
 } catch (CloneNotSupportedException e) {
 //異常處理
 }
 return prototypeClass;
 }
}

原型模式實際上就是實現(xiàn) Cloneable 接口,重寫 clone()方法。
使用原型模式的優(yōu)點:
● 性能優(yōu)良
原型模式是在內(nèi)存二進(jìn)制流的拷貝,要比直接 new 一個對象性能好很多,特別是
要在一個循環(huán)體內(nèi)產(chǎn)生大量的對象時,原型模式可以更好地體現(xiàn)其優(yōu)點。
● 逃避構(gòu)造函數(shù)的約束
這既是它的優(yōu)點也是缺點,直接在內(nèi)存中拷貝,構(gòu)造函數(shù)是不會執(zhí)行的(參見
13.4 節(jié))。
使用場景:
● 資源優(yōu)化場景
類初始化需要消化非常多的資源,這個資源包括數(shù)據(jù)、硬件資源等。
● 性能和安全要求的場景
通過 new 產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限,則可以使用原型模
式。
● 一個對象多個修改者的場景
一個對象需要提供給其他對象訪問,而且各個調(diào)用者可能都需要修改其值時,可以
考慮使用原型模式拷貝多個對象供調(diào)用者使用。
淺拷貝和深拷貝:
淺拷貝:Object 類提供的方法 clone 只是拷貝本對象,其對象內(nèi)部的數(shù)組、引用
對象等都不拷貝,還是指向原生對象的內(nèi)部元素地址,這種拷貝就叫做淺拷貝,其
他的原始類型比如 int、long、char、string(當(dāng)做是原始類型)等都會被拷貝。
注意: 使用原型模式時,引用的成員變量必須滿足兩個條件才不會被拷貝:一是
類的成員變量,而不是方法內(nèi)變量;二是必須是一個可變的引用對象,而不是一個
原始類型或不可變對象。
深拷貝:對私有的類變量進(jìn)行獨立的拷貝
如:thing.arrayList = (ArrayList<String>)this.arrayList.clone();

8.中介者模式

定義:Define an object that encapsulates how a set of objects interact.Mediator
promotes loose coupling by keeping objects from referring to each other
explicitly,and it lets you vary their interaction independently.(用一個中介對象封裝
一系列的對象交互,中介者使各對象不需要顯示地相互作用,從而使其耦合松散,
而且可以獨立地改變它們之間的交互。)
● Mediator 抽象中介者角色
抽象中介者角色定義統(tǒng)一的接口,用于各同事角色之間的通信。
● Concrete Mediator 具體中介者角色
具體中介者角色通過協(xié)調(diào)各同事角色實現(xiàn)協(xié)作行為,因此它必須依賴于各個同事角
色。
● Colleague 同事角色
每一個同事角色都知道中介者角色,而且與其他的同事角色通信的時候,一定要通
過中介者角色協(xié)作。每個同事類的行為分為兩種:一種是同事本身的行為,比如改
變對象本身的狀態(tài),處理自己的行為等,這種行為叫做自發(fā)行為(SelfMethod),與其他的同事類或中介者沒有任何的依賴;第二種是必須依賴中介者
才能完成的行為,叫做依賴方法(Dep-Method)。
通用抽象中介者代碼:

public abstract class Mediator {
 //定義同事類
 protected ConcreteColleague1 c1;
 protected ConcreteColleague2 c2;
 //通過 getter/setter 方法把同事類注入進(jìn)來
 public ConcreteColleague1 getC1() {
 return c1;
 }
 public void setC1(ConcreteColleague1 c1) {
 this.c1 = c1;
 }
 public ConcreteColleague2 getC2() {
 return c2;
}
 public void setC2(ConcreteColleague2 c2) {
 this.c2 = c2;
 }
 //中介者模式的業(yè)務(wù)邏輯
 public abstract void doSomething1();
 public abstract void doSomething2();
}

ps:使用同事類注入而不使用抽象注入的原因是因為抽象類中不具有每個同事類
必須要完成的方法。即每個同事類中的方法各不相同。
問:為什么同事類要使用構(gòu)造函數(shù)注入中介者,而中介者使用 getter/setter 方式注
入同事類呢?
這是因為同事類必須有中介者,而中介者卻可以只有部分同事類。
使用場景:
中介者模式適用于多個對象之間緊密耦合的情況,緊密耦合的標(biāo)準(zhǔn)是:在類圖中出
現(xiàn)了蜘蛛網(wǎng)狀結(jié)構(gòu),即每個類都與其他的類有直接的聯(lián)系。

9.命令模式

定義:Encapsulate a request as an object,thereby letting you parameterize clients
with different requests,queue or log requests,and support undoable operations.
(將一個請求封裝成一個對象,從而讓你使用不同的請求把客戶端參數(shù)化,對請求
排隊或者記錄請求日志,可以提供命令的撤銷和恢復(fù)功能。)
● Receive 接收者角色
該角色就是干活的角色,命令傳遞到這里是應(yīng)該被執(zhí)行的,具體到我們上面的例子
中就是 Group 的三個實現(xiàn)類(需求組,美工組,代碼組)。
● Command 命令角色
需要執(zhí)行的所有命令都在這里聲明。
● Invoker 調(diào)用者角色
接收到命令,并執(zhí)行命令。在例子中,我(項目經(jīng)理)就是這個角色。
使用場景:
認(rèn)為是命令的地方就可以采用命令模式,例如,在 GUI 開發(fā)中,一個按鈕的點擊
是一個命令,可以采用命令模式;模擬 DOS 命令的時候,當(dāng)然也要采用命令模
式;觸發(fā)-反饋機制的處理等。

10.責(zé)任鏈模式

定義:Avoid coupling the sender of a request to its receiver by giving more than
one object a chance to handle the request.Chain the receiving objects and pass
the request along the chain until an object handles it.(使多個對象都有機會處理請
求,從而避免了請求的發(fā)送者和接受者之間的耦合關(guān)系。將這些對象連成一條鏈,
并沿著這條鏈傳遞該請求,直到有對象處理它為止。)
抽象處理者的代碼:

public abstract class Handler {
 private Handler nextHandler;
 //每個處理者都必須對請求做出處理
 public final Response handleMessage(Request request){
 Response response = null;
 //判斷是否是自己的處理級別

if(this.getHandlerLevel().equals(request.getRequestLevel())){
 response = this.echo(request);
 }else{ //不屬于自己的處理級別
 //判斷是否有下一個處理者
 if(this.nextHandler != null){
 response =
this.nextHandler.handleMessage(request);
 }else{
 //沒有適當(dāng)?shù)奶幚碚?,業(yè)務(wù)自行處理
 }
 }
 return response;
 }
 //設(shè)置下一個處理者是誰
 public void setNext(Handler _handler){
 this.nextHandler = _handler;
 }
 //每個處理者都有一個處理級別
 protected abstract Level getHandlerLevel();
 //每個處理者都必須實現(xiàn)處理任務(wù)
 protected abstract Response echo(Request request);
}

抽象的處理者實現(xiàn)三個職責(zé):
一是定義一個請求的處理方法 handleMessage,唯一對外開放的方法;
二是定義一個鏈的編排方法 setNext,設(shè)置下一個處理者;
三是定義了具體的請求者必須實現(xiàn)的兩個方法:定義自己能夠處理的級別
getHandlerLevel 和具體的處理任務(wù) echo。
注意事項:
鏈中節(jié)點數(shù)量需要控制,避免出現(xiàn)超長鏈的情況,一般的做法是在 Handler 中設(shè)置
一個最大節(jié)點數(shù)量,在 setNext 方法中判斷是否已經(jīng)是超過其閾值,超過則不允許
該鏈建立,避免無意識地破壞系統(tǒng)性能。

11.裝飾模式(Decorator Pattern)

定義:Attach additional responsibilities to an object dynamically keeping the
same interface.Decorators provide a flexible alternative to subclassing for
extending functionality.(動態(tài)地給一個對象添加一些額外的職責(zé)。就增加功能來
說,裝飾模式相比生成子類更為靈活。)
● Component 抽象構(gòu)件
Component 是一個接口或者是抽象類,就是定義我們最核心的對象,也就是最原
始的對象,如上面的成績單。
注意:在裝飾模式中,必然有一個最基本、最核心、最原始的接口或抽象類充當(dāng)
Component 抽象構(gòu)件。
● ConcreteComponent 具體構(gòu)件
ConcreteComponent 是最核心、最原始、最基本的接口或抽象類的實現(xiàn),你要裝
飾的就是它。
● Decorator 裝飾角色
一般是一個抽象類,做什么用呢?實現(xiàn)接口或者抽象方法,它里面可不一定有抽象
的方法呀,在它的屬性里必然有一個 private 變量指向 Component 抽象構(gòu)件。
● 具體裝飾角色
ConcreteDecoratorA 和 ConcreteDecoratorB 是兩個具體的裝飾類,你要把你最核
心的、最原始的、最基本的東西裝飾成其他東西,上面的例子就是把一個比較平庸
的成績單裝飾成家長認(rèn)可的成績單。
使用場景:
● 需要擴展一個類的功能,或給一個類增加附加功能。
● 需要動態(tài)地給一個對象增加功能,這些功能可以再動態(tài)地撤銷。
● 需要為一批的兄弟類進(jìn)行改裝或加裝功能,當(dāng)然是首選裝飾模式。

12.策略模式(Strategy Pattern)

定義:Define a family of algorithms,encapsulate each one,and make them
interchangeable.(定義一組算法,將每個算法都封裝起來,并且使它們之間可以
互換。)
● Context 封裝角色
它也叫做上下文角色,起承上啟下封裝作用,屏蔽高層模塊對策略、算法的直接訪
問,封裝可能存在的變化。
● Strategy 抽象策略角色
策略、算法家族的抽象,通常為接口,定義每個策略或算法必須具有的方法和屬
性。各位看官可能要問了,類圖中的 AlgorithmInterface 是什么意思,嘿嘿,
algorithm 是“運算法則”的意思,結(jié)合起來意思就明白了吧。
● ConcreteStrategy 具體策略角色(多個)
實現(xiàn)抽象策略中的操作,該類含有具體的算法。
使用場景:
● 多個類只有在算法或行為上稍有不同的場景。
● 算法需要自由切換的場景。
● 需要屏蔽算法規(guī)則的場景。
注意事項:具體策略數(shù)量超過 4 個,則需要考慮使用混合模式
策略模式擴展:策略枚舉

public enum Calculator {
 //加法運算
 ADD("+"){
 public int exec(int a,int b){
 return a+b;
 }
 },
 //減法運算
 SUB("-"){
 public int exec(int a,int b){
 return a - b;
 }
 };
 String value = "";
 //定義成員值類型
 private Calculator(String _value){
 this.value = _value;
 }
 //獲得枚舉成員的值
 public String getValue(){
 return this.value;
 }
 //聲明一個抽象函數(shù)
 public abstract int exec(int a,int b);
}

定義:
● 它是一個枚舉。
● 它是一個濃縮了的策略模式的枚舉。
注意:
受枚舉類型的限制,每個枚舉項都是 public、final、static 的,擴展性受到了一定
的約束,因此在系統(tǒng)開發(fā)中,策略枚舉一般擔(dān)當(dāng)不經(jīng)常發(fā)生變化的角色。
致命缺陷:
所有的策略都需要暴露出去,由客戶端決定使用哪一個策略。

13.適配器模式(Adapter Pattern)

定義:Convert the interface of a class into another interface clients
expect.Adapter lets classes work together that couldn't otherwise because of
incompatible interfaces.(將一個類的接口變換成客戶端所期待的另一種接口,從
而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。)
類適配器:
● Target 目標(biāo)角色
該角色定義把其他類轉(zhuǎn)換為何種接口,也就是我們的期望接口,例子中的
IUserInfo 接口就是目標(biāo)角色。
● Adaptee 源角色
你想把誰轉(zhuǎn)換成目標(biāo)角色,這個“誰”就是源角色,它是已經(jīng)存在的、運行良好的類
或?qū)ο?,?jīng)過適配器角色的包裝,它會成為一個嶄新、靚麗的角色。
● Adapter 適配器角色
適配器模式的核心角色,其他兩個角色都是已經(jīng)存在的角色,而適配器角色是需要
新建立的,它的職責(zé)非常簡單:把源角色轉(zhuǎn)換為目標(biāo)角色,怎么轉(zhuǎn)換?通過繼承或
是類關(guān)聯(lián)的方式。
使用場景:
你有動機修改一個已經(jīng)投產(chǎn)中的接口時,適配器模式可能是最適合你的模式。比如
系統(tǒng)擴展了,需要使用一個已有或新建立的類,但這個類又不符合系統(tǒng)的接口,怎
么辦?使用適配器模式,這也是我們例子中提到的。
注意事項:
詳細(xì)設(shè)計階段不要考慮使用適配器模式,使用主要場景為擴展應(yīng)用中。
對象適配器:
對象適配器和類適配器的區(qū)別:
類適配器是類間繼承,對象適配器是對象的合成關(guān)系,也可以說是類的關(guān)聯(lián)關(guān)系,
這是兩者的根本區(qū)別。(實際項目中對象適配器使用到的場景相對比較多)。

14.迭代器模式(Iterator Pattern)

定義:Provide a way to access the elements of an aggregate object sequentially
without exposing its underlying representation.(它提供一種方法訪問一個容器對
象中各個元素,而又不需暴露該對象的內(nèi)部細(xì)節(jié)。)
● Iterator 抽象迭代器
抽象迭代器負(fù)責(zé)定義訪問和遍歷元素的接口,而且基本上是有固定的 3 個方法:
first()獲得第一個元素,next()訪問下一個元素,isDone()是否已經(jīng)訪問到底部
(Java 叫做 hasNext()方法)。
● ConcreteIterator 具體迭代器
具體迭代器角色要實現(xiàn)迭代器接口,完成容器元素的遍歷。
● Aggregate 抽象容器
容器角色負(fù)責(zé)提供創(chuàng)建具體迭代器角色的接口,必然提供一個類似 createIterator()
這樣的方法,在 Java 中一般是 iterator()方法。
● Concrete Aggregate 具體容器
具體容器實現(xiàn)容器接口定義的方法,創(chuàng)建出容納迭代器的對象。
ps:迭代器模式已經(jīng)被淘汰,java 中已經(jīng)把迭代器運用到各個聚集類
(collection)中了,使用 java 自帶的迭代器就已經(jīng)滿足我們的需求了。

15.組合模式((Composite Pattern))

定義:Compose objects into tree structures to represent part-whole
hierarchies.Composite lets clients treat individual objects and compositions of
objects uniformly.(將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),使得用
戶對單個對象和組合對象的使用具有一致性。)
● Component 抽象構(gòu)件角色
定義參加組合對象的共有方法和屬性,可以定義一些默認(rèn)的行為或?qū)傩?,比如我?br> 例子中的 getInfo 就封裝到了抽象類中。
● Leaf 葉子構(gòu)件
葉子對象,其下再也沒有其他的分支,也就是遍歷的最小單位。
● Composite 樹枝構(gòu)件
樹枝對象,它的作用是組合樹枝節(jié)點和葉子節(jié)點形成一個樹形結(jié)構(gòu)。
樹枝構(gòu)件的通用代碼:

public class Composite extends Component {
 //構(gòu)件容器
 private ArrayList<Component> componentArrayList = new
ArrayList<Component>();
 //增加一個葉子構(gòu)件或樹枝構(gòu)件
 public void add(Component component){
 this.componentArrayList.add(component);
 }
 //刪除一個葉子構(gòu)件或樹枝構(gòu)件
 public void remove(Component component){
this.componentArrayList.remove(component);
 }
 //獲得分支下的所有葉子構(gòu)件和樹枝構(gòu)件
 public ArrayList<Component> getChildren(){
 return this.componentArrayList;
 }
}

使用場景:
● 維護和展示部分-整體關(guān)系的場景,如樹形菜單、文件和文件夾管理。
● 從一個整體中能夠獨立出部分模塊或功能的場景。
注意:
只要是樹形結(jié)構(gòu),就考慮使用組合模式。

16.觀察者模式(Observer Pattern)

定義:Define a one-to-many dependency between objects so that when one
object changes state,all its dependents are notified and updated automatically.
(定義對象間一種一對多的依賴關(guān)系,使得每當(dāng)一個對象改變狀態(tài),則所有依賴于
它的對象都會得到通知并被自動更新。)
● Subject 被觀察者
定義被觀察者必須實現(xiàn)的職責(zé),它必須能夠動態(tài)地增加、取消觀察者。它一般是抽
象類或者是實現(xiàn)類,僅僅完成作為被觀察者必須實現(xiàn)的職責(zé):管理觀察者并通知觀
察者。
● Observer 觀察者
觀察者接收到消息后,即進(jìn)行 update(更新方法)操作,對接收到的信息進(jìn)行處
理。
● ConcreteSubject 具體的被觀察者
定義被觀察者自己的業(yè)務(wù)邏輯,同時定義對哪些事件進(jìn)行通知。
● ConcreteObserver 具體的觀察者
每個觀察在接收到消息后的處理反應(yīng)是不同,各個觀察者有自己的處理邏輯。
被觀察者通用代碼:

public abstract class Subject {
 //定義一個觀察者數(shù)組
 private Vector<Observer> obsVector = new Vector<Observer>();
 //增加一個觀察者
 public void addObserver(Observer o){
 this.obsVector.add(o);
 }
 //刪除一個觀察者
 public void delObserver(Observer o){
 this.obsVector.remove(o);
 }
 //通知所有觀察者
 public void notifyObservers(){
 for(Observer o:this.obsVector){
 o.update();
}
 }
}

使用場景:
● 關(guān)聯(lián)行為場景。需要注意的是,關(guān)聯(lián)行為是可拆分的,而不是“組合”關(guān)系。
● 事件多級觸發(fā)場景。
● 跨系統(tǒng)的消息交換場景,如消息隊列的處理機制。
注意:
● 廣播鏈的問題
在一個觀察者模式中最多出現(xiàn)一個對象既是觀察者也是被觀察者,也就是說消息最
多轉(zhuǎn)發(fā)一次(傳遞兩次)。
● 異步處理問題
觀察者比較多,而且處理時間比較長,采用異步處理來考慮線程安全和隊列的問
題。

17.門面模式(Facade Pattern)

定義:Provide a unified interface to a set of interfaces in a subsystem.Facade
defines a higher-level interface that makes the subsystem easier to use.(要求一
個子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個統(tǒng)一的對象進(jìn)行。門面模式提供一個
高層次的接口,使得子系統(tǒng)更易于使用。)
● Facade 門面角色
客戶端可以調(diào)用這個角色的方法。此角色知曉子系統(tǒng)的所有功能和責(zé)任。一般情況
下,本角色會將所有從客戶端發(fā)來的請求委派到相應(yīng)的子系統(tǒng)去,也就說該角色沒
有實際的業(yè)務(wù)邏輯,只是一個委托類。
● subsystem 子系統(tǒng)角色
可以同時有一個或者多個子系統(tǒng)。每一個子系統(tǒng)都不是一個單獨的類,而是一個類
的集合。子系統(tǒng)并不知道門面的存在。對于子系統(tǒng)而言,門面僅僅是另外一個客戶
端而已。
使用場景:
● 為一個復(fù)雜的模塊或子系統(tǒng)提供一個供外界訪問的接口
● 子系統(tǒng)相對獨立——外界對子系統(tǒng)的訪問只要黑箱操作即可
● 預(yù)防低水平人員帶來的風(fēng)險擴散
注意:
●一個子系統(tǒng)可以有多個門面
●門面不參與子系統(tǒng)內(nèi)的業(yè)務(wù)邏輯

18.備忘錄模式(Memento Pattern)

定義:Without violating encapsulation,capture and externalize an object's internal
state so that the object can be restored to this state later.(在不破壞封裝性的前提
下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該
對象恢復(fù)到原先保存的狀態(tài)。)
● Originator 發(fā)起人角色
記錄當(dāng)前時刻的內(nèi)部狀態(tài),負(fù)責(zé)定義哪些屬于備份范圍的狀態(tài),負(fù)責(zé)創(chuàng)建和恢復(fù)備
忘錄數(shù)據(jù)。
● Memento 備忘錄角色(簡單的 javabean)
負(fù)責(zé)存儲 Originator 發(fā)起人對象的內(nèi)部狀態(tài),在需要的時候提供發(fā)起人需要的內(nèi)部
狀態(tài)。
● Caretaker 備忘錄管理員角色(簡單的 javabean)
對備忘錄進(jìn)行管理、保存和提供備忘錄。
使用場景:
● 需要保存和恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場景。
● 提供一個可回滾(rollback)的操作。
● 需要監(jiān)控的副本場景中。
● 數(shù)據(jù)庫連接的事務(wù)管理就是用的備忘錄模式。
注意:
●備忘錄的生命期
●備忘錄的性能
不要在頻繁建立備份的場景中使用備忘錄模式(比如一個 for 循環(huán)中)。
clone 方式備忘錄:
● 發(fā)起人角色融合了發(fā)起人角色和備忘錄角色,具有雙重功效
多狀態(tài)的備忘錄模式
● 增加了一個 BeanUtils 類,其中 backupProp 是把發(fā)起人的所有屬性值轉(zhuǎn)換到
HashMap 中,方便備忘錄角色存儲。restoreProp 方法則是把 HashMap 中的值返
回到發(fā)起人角色中。
BeanUtil 工具類代碼:

public class BeanUtils {
 //把 bean 的所有屬性及數(shù)值放入到 Hashmap 中
 public static HashMap<String,Object> backupProp(Object bean){
 HashMap<String,Object> result = new
HashMap<String,Object>();
 try {
 //獲得 Bean 描述
 BeanInfo
beanInfo=Introspector.getBeanInfo(bean.getClass());
 //獲得屬性描述
 PropertyDescriptor[]
descriptors=beanInfo.getPropertyDescriptors();
 //遍歷所有屬性
 for(PropertyDescriptor des:descriptors){
 //屬性名稱
String fieldName = des.getName();
 //讀取屬性的方法
Method getter = des.getReadMethod();
 //讀取屬性值
Object fieldValue=getter.invoke(bean,new
Object[]{});
 if(!fieldName.equalsIgnoreCase("class")){
 result.put(fieldName, fieldValue);
 }
 }
 } catch (Exception e) {
 //異常處理
 }
 return result;
 }
 //把 HashMap 的值返回到 bean 中
 public static void restoreProp(Object bean,HashMap<String,Object>
propMap){
try {
 //獲得 Bean 描述
 BeanInfo beanInfo =
Introspector.getBeanInfo(bean.getClass());
 //獲得屬性描述
 PropertyDescriptor[] descriptors =
beanInfo.getPropertyDescriptors();
 //遍歷所有屬性
 for(PropertyDescriptor des:descriptors){
 //屬性名稱
 String fieldName = des.getName();
 //如果有這個屬性
 if(propMap.containsKey(fieldName)){
 //寫屬性的方法
Method setter = des.getWriteMethod();
 setter.invoke(bean, new
Object[]{propMap.get(fieldName)});
 }
 }
 } catch (Exception e) {
 //異常處理
 System.out.println("shit");
 e.printStackTrace();
 }
 }
}

多備份的備忘錄:略
封裝得更好一點:保證只能對發(fā)起人可讀
●建立一個空接口 IMemento——什么方法屬性都沒有的接口,然后在發(fā)起人
Originator 類中建立一個內(nèi)置類(也叫做類中類)Memento 實現(xiàn) IMemento 接口,
同時也實現(xiàn)自己的業(yè)務(wù)邏輯。

19.訪問者模式(Visitor Pattern)

定義:Represent an operation to be performed on the elements of an object
structure. Visitor lets you define a new operation without changing the classes of
the elements on which it operates. (封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的
操作,它可以在不改變數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。)
● Visitor——抽象訪問者
抽象類或者接口,聲明訪問者可以訪問哪些元素,具體到程序中就是 visit 方法的
參數(shù)定義哪些對象是可以被訪問的。
● ConcreteVisitor——具體訪問者
它影響訪問者訪問到一個類后該怎么干,要做什么事情。
● Element——抽象元素
接口或者抽象類,聲明接受哪一類訪問者訪問,程序上是通過 accept 方法中的參
數(shù)來定義的。
● ConcreteElement——具體元素
實現(xiàn) accept 方法,通常是 visitor.visit(this),基本上都形成了一種模式了。
● ObjectStruture——結(jié)構(gòu)對象
元素產(chǎn)生者,一般容納在多個不同類、不同接口的容器,如 List、Set、Map 等,
在項目中,一般很少抽象出這個角色。
使用場景:
● 一個對象結(jié)構(gòu)包含很多類對象,它們有不同的接口,而你想對這些對象實施一些
依賴于其具體類的操作,也就說是用迭代器模式已經(jīng)不能勝任的情景。
● 需要對一個對象結(jié)構(gòu)中的對象進(jìn)行很多不同并且不相關(guān)的操作,而你想避免讓這
些操作“污染”這些對象的類。

20.狀態(tài)模式(復(fù)雜)

定義:Allow an object to alter its behavior when its internal state changes.The
object will appear to change its class.(當(dāng)一個對象內(nèi)在狀態(tài)改變時允許其改變行
為,這個對象看起來像改變了其類。)
● State——抽象狀態(tài)角色
接口或抽象類,負(fù)責(zé)對象狀態(tài)定義,并且封裝環(huán)境角色以實現(xiàn)狀態(tài)切換。
● ConcreteState——具體狀態(tài)角色
每一個具體狀態(tài)必須完成兩個職責(zé):本狀態(tài)的行為管理以及趨向狀態(tài)處理,通俗地
說,就是本狀態(tài)下要做的事情,以及本狀態(tài)如何過渡到其他狀態(tài)。
● Context——環(huán)境角色
定義客戶端需要的接口,并且負(fù)責(zé)具體狀態(tài)的切換。
使用場景:
● 行為隨狀態(tài)改變而改變的場景
這也是狀態(tài)模式的根本出發(fā)點,例如權(quán)限設(shè)計,人員的狀態(tài)不同即使執(zhí)行相同的行
為結(jié)果也會不同,在這種情況下需要考慮使用狀態(tài)模式。
● 條件、分支判斷語句的替代者
注意:
狀態(tài)模式適用于當(dāng)某個對象在它的狀態(tài)發(fā)生改變時,它的行為也隨著發(fā)生比較大的
變化,也就是說在行為受狀態(tài)約束的情況下可以使用狀態(tài)模式,而且使用時對象的
狀態(tài)最好不要超過 5 個。

21.解釋器模式(Interpreter Pattern)

(少用)
定義:Given a language, define a representation for its grammar along with an
interpreter that uses the representation to interpret sentences in the language.
(給定一門語言,定義它的文法的一種表示,并定義一個解釋器,該解釋器使用該
表示來解釋語言中的句子。)
● AbstractExpression——抽象解釋器
具體的解釋任務(wù)由各個實現(xiàn)類完成,具體的解釋器分別由 TerminalExpression 和
Non-terminalExpression 完成。
● TerminalExpression——終結(jié)符表達(dá)式
實現(xiàn)與文法中的元素相關(guān)聯(lián)的解釋操作,通常一個解釋器模式中只有一個終結(jié)符表
達(dá)式,但有多個實例,對應(yīng)不同的終結(jié)符。具體到我們例子就是 VarExpression
類,表達(dá)式中的每個終結(jié)符都在棧中產(chǎn)生了一個 VarExpression 對象。
● NonterminalExpression——非終結(jié)符表達(dá)式
文法中的每條規(guī)則對應(yīng)于一個非終結(jié)表達(dá)式,具體到我們的例子就是加減法規(guī)則分
別對應(yīng)到 AddExpression 和 SubExpression 兩個類。非終結(jié)符表達(dá)式根據(jù)邏輯的
復(fù)雜程度而增加,原則上每個文法規(guī)則都對應(yīng)一個非終結(jié)符表達(dá)式。
● Context——環(huán)境角色
具體到我們的例子中是采用 HashMap 代替。
使用場景:
● 重復(fù)發(fā)生的問題可以使用解釋器模式
● 一個簡單語法需要解釋的場景
注意:
盡量不要在重要的模塊中使用解釋器模式,否則維護會是一個很大的問題。在項目
中可以使用 shell、JRuby、Groovy 等腳本語言來代替解釋器模式,彌補 Java 編
譯型語言的不足。

22.享元模式(Flyweight Pattern)

定義:Use sharing to support large numbers of fine-grained objects efficiently.
(使用共享對象可有效地支持大量的細(xì)粒度的對象。)
對象的信息分為兩個部分:內(nèi)部狀態(tài)(intrinsic)與外部狀態(tài)(extrinsic)。
● 內(nèi)部狀態(tài)
內(nèi)部狀態(tài)是對象可共享出來的信息,存儲在享元對象內(nèi)部并且不會隨環(huán)境改變而改
變。
● 外部狀態(tài)
外部狀態(tài)是對象得以依賴的一個標(biāo)記,是隨環(huán)境改變而改變的、不可以共享的狀
態(tài)。
● Flyweight——抽象享元角色
它簡單地說就是一個產(chǎn)品的抽象類,同時定義出對象的外部狀態(tài)和內(nèi)部狀態(tài)的接口
或?qū)崿F(xiàn)。
● ConcreteFlyweight——具體享元角色
具體的一個產(chǎn)品類,實現(xiàn)抽象角色定義的業(yè)務(wù)。該角色中需要注意的是內(nèi)部狀態(tài)處
理應(yīng)該與環(huán)境無關(guān),不應(yīng)該出現(xiàn)一個操作改變了內(nèi)部狀態(tài),同時修改了外部狀態(tài),
這是絕對不允許的。
● unsharedConcreteFlyweight——不可共享的享元角色
不存在外部狀態(tài)或者安全要求(如線程安全)不能夠使用共享技術(shù)的對象,該對象
一般不會出現(xiàn)在享元工廠中。
● FlyweightFactory——享元工廠
職責(zé)非常簡單,就是構(gòu)造一個池容器,同時提供從池中獲得對象的方法。
享元工廠的代碼:

public class FlyweightFactory {
 //定義一個池容器
 private static HashMap<String,Flyweight> pool= new
HashMap<String,Flyweight>();
 //享元工廠
 public static Flyweight getFlyweight(String Extrinsic){
 //需要返回的對象
 Flyweight flyweight = null;
 //在池中沒有該對象
 if(pool.containsKey(Extrinsic)){
 flyweight = pool.get(Extrinsic);
 }else{
 //根據(jù)外部狀態(tài)創(chuàng)建享元對象
 flyweight = new ConcreteFlyweight1(Extrinsic);
 //放置到池中
 pool.put(Extrinsic, flyweight);
 }
 return flyweight;
 }
}

使用場景:
● 系統(tǒng)中存在大量的相似對象。
● 細(xì)粒度的對象都具備較接近的外部狀態(tài),而且內(nèi)部狀態(tài)與環(huán)境無關(guān),也就是說對
象沒有特定身份。
● 需要緩沖池的場景。
注意:
● 享元模式是線程不安全的,只有依靠經(jīng)驗,在需要的地方考慮一下線程安全,在
大部分場景下不用考慮。對象池中的享元對象盡量多,多到足夠滿足為止。
● 性能安全:外部狀態(tài)最好以 java 的基本類型作為標(biāo)志,如 String,int,可以提
高效率。

23.橋梁模式(Bridge Pattern)

定義:Decouple an abstraction from its implementation so that the two can vary
independently.(將抽象和實現(xiàn)解耦,使得兩者可以獨立地變化。)
● Abstraction——抽象化角色
它的主要職責(zé)是定義出該角色的行為,同時保存一個對實現(xiàn)化角色的引用,該角色
一般是抽象類。
● Implementor——實現(xiàn)化角色
它是接口或者抽象類,定義角色必需的行為和屬性。
● RefinedAbstraction——修正抽象化角色
它引用實現(xiàn)化角色對抽象化角色進(jìn)行修正。
● ConcreteImplementor——具體實現(xiàn)化角色
它實現(xiàn)接口或抽象類定義的方法和屬性。
使用場景:
● 不希望或不適用使用繼承的場景
● 接口或抽象類不穩(wěn)定的場景
● 重用性要求較高的場景
注意:
發(fā)現(xiàn)類的繼承有 N 層時,可以考慮使用橋梁模式。橋梁模式主要考慮如何拆分抽
象和實現(xiàn)。
設(shè)計原則:
●Single Responsibility Principle:單一職責(zé)原則
單一職責(zé)原則有什么好處:
● 類的復(fù)雜性降低,實現(xiàn)什么職責(zé)都有清晰明確的定義;
● 可讀性提高,復(fù)雜性降低,那當(dāng)然可讀性提高了;
● 可維護性提高,可讀性提高,那當(dāng)然更容易維護了;
●變更引起的風(fēng)險降低,變更是必不可少的,如果接口的單一職責(zé)做得好,一個接
口修改只對相應(yīng)的實現(xiàn)類有影響,對其他的接口無影響,這對系統(tǒng)的擴展性、維護
性都有非常大的幫助。
ps:接口一定要做到單一職責(zé),類的設(shè)計盡量做到只有一個原因引起變化。
單一職責(zé)原則提出了一個編寫程序的標(biāo)準(zhǔn),用“職責(zé)”或“變化原因”來衡量接口
或類設(shè)計得是否優(yōu)良,但是“職責(zé)”和“變化原因”都是不可度量的,因項目而異,因
環(huán)境而異。
● Liskov Substitution Principle:里氏替換原則
定義:Functions that use pointers or references to base classes must be able to
use objects of derived classes without knowing it.
(所有引用基類的地方必須能透明地使用其子類的對象。)
通俗點講,只要父類能出現(xiàn)的地方子類就可以出現(xiàn),而且替換為子類也不會產(chǎn)生任
何錯誤或異常,使用者可能根本就不需要知道是父類還是子類。但是,反過來就不
行了,有子類出現(xiàn)的地方,父類未必就能適應(yīng)。
定義中包含的四層含義:
1.子類必須完全實現(xiàn)父類的方法
2.子類可以有自己的個性
3.覆蓋或?qū)崿F(xiàn)父類的方法時輸入?yún)?shù)可以被放大
如果父類的輸入?yún)?shù)類型大于子類的輸入?yún)?shù)類型,會出現(xiàn)父類存在的地
方,子類未必會存在,因為一旦把子類作為參數(shù)傳入,調(diào)用者很可能進(jìn)入子類的方
法范疇。

  1. 覆寫或?qū)崿F(xiàn)父類的方法時輸出結(jié)果可以被縮小
    父類的一個方法的返回值是一個類型 T,子類的相同方法(重載或覆寫)的返
    回值為 S,那么里氏替換原則就要求 S 必須小于等于 T,也就是說,要么 S 和 T
    是同一個類型,要么 S 是 T 的子類。
    ● Interface Segregation Principle:接口隔離原則
    接口分為兩種:
    實例接口(Object Interface):Java 中的類也是一種接口
    類接口(Class Interface): Java 中經(jīng)常使用 Interface 關(guān)鍵字定義的接口
    隔離:建立單一接口,不要建立臃腫龐大的接口;即接口要盡量細(xì)化,同時接口中
    的方法要盡量少。
    接口隔離原則與單一職責(zé)原則的不同:接口隔離原則與單一職責(zé)的審視角度是不相
    同的,單一職責(zé)要求的是類和接口職責(zé)單一,注重的是職責(zé),這是業(yè)務(wù)邏輯上的劃
    分,而接口隔離原則要求接口的方法盡量少。
    ● Dependence Inversion Principle:依賴倒置原則
    原始定義:
    ①高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象;
    ②抽象不應(yīng)該依賴細(xì)節(jié)(實現(xiàn)類);
    ③細(xì)節(jié)應(yīng)該依賴抽象。
    依賴倒置原則在 java 語言中的體現(xiàn):
    ①模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是
    通過接口或抽象類產(chǎn)生的;
    ②接口或抽象類不依賴于實現(xiàn)類;
    ③實現(xiàn)類依賴接口或抽象類。
    依賴的三種寫法:
    ①構(gòu)造函數(shù)傳遞依賴對象(構(gòu)造函數(shù)注入)
    ②Setter 方法傳遞依賴對象(setter 依賴注入)
    ③接口聲明依賴對象(接口注入)
    使用原則:
    依賴倒置原則的本質(zhì)就是通過抽象(接口或抽象類)使各個類或模塊的實現(xiàn)彼此獨
    立,不互相影響,實現(xiàn)模塊間的松耦合,我們怎么在項目中使用這個規(guī)則呢?只要
    遵循以下的幾個規(guī)則就可以:
    ①每個類盡量都有接口或抽象類,或者抽象類和接口兩者都具備
    ②變量的表面類型盡量是接口或者是抽象類
    ③任何類都不應(yīng)該從具體類派生(只要不超過兩層的繼承是可以忍受的)
    ④盡量不要復(fù)寫基類的方法
    ⑤結(jié)合里氏替換原則使用
    ●Open Closed Principle:開閉原則
    定義:軟件實體應(yīng)該對擴展開放,對修改關(guān)閉。
    其含義是說一個軟件實體應(yīng)該通過擴展來實現(xiàn)變化,而不是通過修改已有的代碼來
    實現(xiàn)變化。
    軟件實體:項目或軟件產(chǎn)品中按照一定的邏輯規(guī)則劃分的模塊、抽象和類、方法。
    變化的三種類型:
    ①邏輯變化
    只變化一個邏輯,而不涉及其他模塊,比如原有的一個算法是 ab+c,現(xiàn)在需要修
    改為 a
    b*c,可以通過修改原有類中的方法的方式來完成,前提條件是所有依賴或
    關(guān)聯(lián)類都按照相同的邏輯處理。
    ②子模塊變化
    一個模塊變化,會對其他的模塊產(chǎn)生影響,特別是一個低層次的模塊變化必然引起
    高層模塊的變化,因此在通過擴展完成變化時,高層次的模塊修改是必然的。
    ③可見視圖變化
    可見視圖是提供給客戶使用的界面,如 JSP 程序、Swing 界面等,該部分的變化
    一般會引起連鎖反應(yīng)(特別是在國內(nèi)做項目,做歐美的外包項目一般不會影響太
    大)。可以通過擴展來完成變化,這要看我們原有的設(shè)計是否靈活。

結(jié)尾
希望讀到這的您能轉(zhuǎn)發(fā)分享和關(guān)注一下我,以后還會更新技術(shù)干貨,謝謝您的支持!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容