引
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。
有三個(gè)分類:
- 創(chuàng)建型模式:對(duì)象實(shí)例化的模式,創(chuàng)建型模式用于解耦對(duì)象的實(shí)例化過(guò)程。
- 結(jié)構(gòu)型模式:把類或?qū)ο蠼Y(jié)合在一起形成一個(gè)更大的結(jié)構(gòu)。
- 行為型模式:類和對(duì)象如何交互,及劃分責(zé)任和算法。
注:所有圖片來(lái)源于網(wǎng)絡(luò),如有侵權(quán)立刻刪除。
單例模式
定義
確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,這個(gè)類稱為單例類,它提供全局訪問(wèn)的方法。
組成
單例(Singleton)

代碼模型
//雙重檢查模式(DCL)
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){
}
public static Singleton getInstance() {
if (instance== null) {
synchronized (Singleton.class) {
if (instance== null) {
instance= new Singleton();
}
}
}
return singleton;
}
}
//靜態(tài)內(nèi)部類
public class Singleton {
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
//容器類實(shí)現(xiàn)
public class SingletonManager {
private static Map<String,Object> objMap = new HashMap<String,Object>();
private SingletonManager(){}
public static void registerService(String key,Object instance){
if (!objMap.containsKey(key)){
objMap.put(key,instance);
}
}
public static Object getInstance(String key){
return objMap.get(key);
}
}
優(yōu)點(diǎn)
- 提供了對(duì)唯一實(shí)例的受控訪問(wèn)
- 僅存在一個(gè)實(shí)例對(duì)象,節(jié)約系統(tǒng)資源
缺點(diǎn)
- 單例模式無(wú)抽象層,不易拓展
- 單例模式的職責(zé)過(guò)重,違背了單一職責(zé)原則
適用范圍
系統(tǒng)只需要一個(gè)實(shí)例對(duì)象,調(diào)用類的單個(gè)實(shí)例只允許使用一個(gè)公共訪問(wèn)點(diǎn),除了該公共訪問(wèn)點(diǎn),不能通過(guò)其他途徑訪問(wèn)該實(shí)例。
使用實(shí)例
通過(guò)Context獲取系統(tǒng)級(jí)別的服務(wù)時(shí),這些系統(tǒng)服務(wù)其實(shí)就是單例模式實(shí)現(xiàn)的,使用了容器實(shí)現(xiàn)的單例模式。
//使用LayoutInflater加載布局時(shí)
LayoutInflater.from(mContext).inflate(mLayoutId, null);
public static LayoutInflater from(Context context) {
//獲取系統(tǒng)服務(wù)
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
//SYSTEM_SERVICE_FETCHERS為鍵值對(duì)容器,用來(lái)存儲(chǔ)生成的SystemService
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
//SYSTEM_SERVICE_FETCHERS的初始化
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
//LayoutInflater的創(chuàng)建加入在一個(gè)靜態(tài)的代碼塊中進(jìn)行注冊(cè)服務(wù),第一次加載該類的時(shí)候執(zhí)行,并且只執(zhí)行一次,保證實(shí)例的唯一性
static {
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
}
建造者模式
定義
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。
組成
- Builder:抽象建造者,該類同樣為抽象類,規(guī)范Product的組建,一般由子類實(shí)現(xiàn)具體Product的構(gòu)建過(guò)程;
- ConcreteBuilder:具體建造者,繼承自Builder,構(gòu)建具體的Product;
- Director:指揮者,統(tǒng)一組裝過(guò)程,作用主要有兩個(gè):一方面它隔離了客戶與生產(chǎn)過(guò)程;另一方面它負(fù)責(zé)控制產(chǎn)品的生成過(guò)程;
- Product:產(chǎn)品角色,該類為一般為抽象類,定義Product的公共屬性配置;

代碼模型
public class Director {
private Builder builder;
// 構(gòu)造產(chǎn)品
public void construct() {
builder = new ConcreteBuilder();
builder.buildPart1();
builder.buildPart2();
}
}
abstract public class Builder {
// 構(gòu)造"產(chǎn)品的Part1"的接口
public abstract void buildPart1();
// 構(gòu)造"產(chǎn)品的Part2"的接口
public abstract void buildPart2();
// 返回產(chǎn)品
public abstract Product retrieveResult();
}
public class ConcreteBuilder {
private Product product = new Product();
public void buildPart1() {
// 參見(jiàn)產(chǎn)品的Part1
}
public void buildPart2() {
// 參見(jiàn)產(chǎn)品的Part2
}
public Product retrieveResult() {
return product;
}
}
public class Product {
// 產(chǎn)品組成部分...
}
優(yōu)點(diǎn)
- 封裝性,使用建造者模式可以使客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)
- 建造者獨(dú)立,容易擴(kuò)展
- 可以更加精細(xì)地控制產(chǎn)品的創(chuàng)建過(guò)程
缺點(diǎn)
如果產(chǎn)品的內(nèi)部變化復(fù)雜,可能會(huì)導(dǎo)致需要定義很多具體建造者類來(lái)實(shí)現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大。
適用范圍
- 需要生成的產(chǎn)品對(duì)象有復(fù)雜的內(nèi)部結(jié)構(gòu),這些產(chǎn)品對(duì)象通常包含多個(gè)成員屬性。
- 需要生成的產(chǎn)品對(duì)象的屬性相互依賴,需要指定其生成順序。
- 隔離復(fù)雜對(duì)象的創(chuàng)建和使用,并使得相同的創(chuàng)建過(guò)程可以創(chuàng)建不同的產(chǎn)品。
使用實(shí)例
Retrofit.Builder就是一個(gè)簡(jiǎn)化版的建造者模式,Retrofit直接對(duì)應(yīng)Product,并沒(méi)有基于抽象Product進(jìn)行擴(kuò)展;Retrofit.Builder對(duì)應(yīng)ConcreteBuilder,也沒(méi)有基于抽象Builder進(jìn)行擴(kuò)展,同時(shí)省略了Director,并在Retrofit.Builder每個(gè)setter方法都返回自身,使得客戶端代碼可以鏈?zhǔn)秸{(diào)用,整個(gè)構(gòu)建過(guò)程更加簡(jiǎn)單。
Retrofit retrofitBuilder = new Retrofit.Builder()
.baseUrl(NetworkConfig.getNewBaseUrl())
.client(mOkHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(CustomGsonConverterFactory.create())
.build();
工廠模式
定義
定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類。工廠方法使一個(gè)類的實(shí)例化延遲到其子類。
組成
- 抽象工廠(Factory)
- 具體工廠(ConcreteFactory)
- 抽象產(chǎn)品(Product)
- 具體產(chǎn)品(ConcreteProduct)。

代碼模型
//抽象工廠:提供“創(chuàng)建產(chǎn)品”的函數(shù)接口,并由其子類實(shí)現(xiàn)。
public interface Factory {
public Product newInstance() ;
}
//具體工廠:實(shí)現(xiàn)了抽象工廠提供的“創(chuàng)建產(chǎn)品”接口。
public class ConcreteFactory1 implements Factory {
public Product newInstance() {
return new ConcreteProduct1();
}
}
public class ConcreteFactory2 implements Factory {
public Product newInstance() {
return new ConcreteProduct2();
}
}
//抽象產(chǎn)品:提供了產(chǎn)品的公用方法函數(shù)
public interface Product {
}
//具體產(chǎn)品:實(shí)現(xiàn)了抽象產(chǎn)品的函數(shù)接口。
public class ConcreteProduct1 implements Product {
public ConcreteProduct1() {
// do something
}
}
public class ConcreteProduct2 implements Product {
public ConcreteProduct2() {
// do something
}
}
優(yōu)點(diǎn)
- 封裝性良好,代碼結(jié)構(gòu)清晰。
- 拓展性優(yōu)秀。
- 屏蔽產(chǎn)品類,客戶無(wú)需關(guān)心創(chuàng)建細(xì)節(jié),僅需關(guān)心對(duì)應(yīng)工廠。
- 典型的解耦框架,符合單一職責(zé)原則(具體的工廠只負(fù)責(zé)對(duì)應(yīng)的產(chǎn)品),里氏替換原則(子類能覆蓋父類對(duì)象)
缺點(diǎn)
- 新增產(chǎn)品時(shí),需要新增對(duì)應(yīng)的具體工廠類,增加了系統(tǒng)的復(fù)雜度。
- 為了拓展性引入了抽象層,增加了系統(tǒng)的理解難度。
適用環(huán)境
需要靈活的、可擴(kuò)展的框架時(shí),可以考慮采用工廠方法模式。
使用實(shí)例
Retrofit的CallAdapter創(chuàng)建使用了工廠模式。
//CallAdapter<T> 為抽象產(chǎn)品
public interface CallAdapter<T> {
Type responseType();
<R> T adapt(Call<R> call);
//allAdapter.Factory為抽象工廠類
abstract class Factory {
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
而它的具體工廠的實(shí)現(xiàn)類,已RxJava2CallAdapterFactory為例
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
// 省略代碼
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 省略代碼
//此處的RxJava2CallAdapter即為具體產(chǎn)品類
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
// 省略代碼
}
}
抽象工廠模式
定義
為創(chuàng)建一組相關(guān)或相互依賴的對(duì)象提供一個(gè)接口,而且無(wú)須指定它們的具體類。
產(chǎn)品等級(jí)結(jié)構(gòu) :產(chǎn)品等級(jí)結(jié)構(gòu)即產(chǎn)品的繼承結(jié)構(gòu),如一個(gè)抽象類是電視機(jī),其子類有海爾電視機(jī)、海信電視機(jī)、TCL電視機(jī),則抽象電視機(jī)與具體品牌的電視機(jī)之間構(gòu)成了一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),抽象電視機(jī)是父類,而具體品牌的電視機(jī)是其子類。
產(chǎn)品族 :在抽象工廠模式中,產(chǎn)品族是指由同一個(gè)工廠生產(chǎn)的,位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中的一組產(chǎn)品,如海爾電器工廠生產(chǎn)的海爾電視機(jī)、海爾電冰箱,海爾電視機(jī)位于電視機(jī)產(chǎn)品等級(jí)結(jié)構(gòu)中,海爾電冰箱位于電冰箱產(chǎn)品等級(jí)結(jié)構(gòu)中。
組成
- 抽象工廠(Factory)
- 具體工廠(ConcreteFactory)
- 抽象產(chǎn)品(Product)
- 具體產(chǎn)品(ConcreteProduct)。

抽象工廠模式與工廠方法模式的區(qū)別:
在工廠方法模式中,"抽象產(chǎn)品"只有一個(gè),而在抽象工廠模式中,"抽象產(chǎn)品"有很多個(gè)!在工廠方法模式中,是由"具體工廠"決定返回哪一類產(chǎn)品;然后,抽象工廠中,是由"客戶端"決定返回哪一類產(chǎn)品。
代碼模型
public interface Factory {
public ProductA newProductA();
public ProductB newProductB();
}
public class ConcreteFactory1 implements Factory {
public ProductA newProductA() {
return new ConcreteProductA1();
}
public ProductB newProductB();
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 implements Factory {
public ProductA newProductA2() {
return new ConcreteProduct1();
}
public ProductB newProductB2();
return new ConcreteProduct1();
}
}
public interface ProductA {
}
public class ProductA1 implements ProductA {
}
public class ProductA2 implements ProductA {
}
public interface ProductB {
}
public class ProductB1 implements ProductB {
}
public class ProductB2 implements ProductB {
}
優(yōu)點(diǎn)
- 封裝性良好,代碼結(jié)構(gòu)清晰。
- 拓展性優(yōu)秀。增加新的具體工廠和產(chǎn)品族很方便。
- 當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí),它能夠保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。這對(duì)一些需要根據(jù)當(dāng)前環(huán)境來(lái)決定其行為的軟件系統(tǒng)來(lái)說(shuō),是一種非常實(shí)用的設(shè)計(jì)模式。
缺點(diǎn)
- 在添加新的產(chǎn)品對(duì)象時(shí),難以擴(kuò)展抽象工廠來(lái)生產(chǎn)新種類的產(chǎn)品,這是因?yàn)樵诔橄蠊S角色中規(guī)定了所有可能被創(chuàng)建的產(chǎn)品集合,要支持新種類的產(chǎn)品就意味著要對(duì)該接口進(jìn)行擴(kuò)展,而這將涉及到對(duì)抽象工廠角色及其所有子類的修改,顯然會(huì)帶來(lái)較大的不便。
- 開(kāi)閉原則的傾斜性(增加新的工廠和產(chǎn)品族容易,增加新的產(chǎn)品等級(jí)結(jié)構(gòu)麻煩)。
適用環(huán)境
一個(gè)對(duì)象族(或是一組沒(méi)有任何關(guān)系的對(duì)象)都有相同的約束,則可以使用抽象工廠模式。
例如一個(gè)文本編輯器和一個(gè)圖片處理器,都是軟件實(shí)體,但是Unix下的文本編輯器和Windows下的文本編輯器雖然功能和界面都相同,但是代碼實(shí)現(xiàn)是不同的,圖片處理器也有類似情況。也就是具有了共同的約束條件:操作系統(tǒng)類型。于是我們可以使用抽象工廠模式,產(chǎn)生不同操作系統(tǒng)下的編輯器和圖片處理器
使用實(shí)例
Retrofit中CallAdapter的使用的設(shè)計(jì)模式即為抽象工廠模式
public interface Converter<F, T> {
T convert(F value) throws IOException;
//抽象工廠
abstract class Factory {
//Converter<ResponseBody, ?>為抽象產(chǎn)品1
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
//Converter<?, RequestBody>為抽象產(chǎn)品2
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
//省略部分代碼
}
}
這里以GsonConverterFactory為例子
//具體工廠
public final class GsonConverterFactory extends Converter.Factory {
// 省略代碼
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//GsonResponseBodyConverter<>為具體產(chǎn)品1
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//GsonRequestBodyConverter<>為具體產(chǎn)品2
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
簡(jiǎn)單工廠模式
定義
又被稱為"靜態(tài)工廠方法模式"。它屬于"創(chuàng)建模式"(創(chuàng)建對(duì)象的模式),并且是"工廠方法"模式的一種特殊實(shí)現(xiàn)。
組成
- 工廠(Factory)
- 抽象產(chǎn)品(Product)
- 具體產(chǎn)品(ConcreteProduct)。

工廠模式與簡(jiǎn)單工廠模式的區(qū)別
工廠方法模式是簡(jiǎn)單工廠模式的進(jìn)一步抽象和推廣。由于使用了面向?qū)ο蟮亩鄳B(tài)性,工廠方法模式保持了簡(jiǎn)單工廠模式的優(yōu)點(diǎn),而且克服了它的缺點(diǎn)。在工廠方法模式中,核心的工廠類不再負(fù)責(zé)所有產(chǎn)品的創(chuàng)建,而是將具體創(chuàng)建工作交給子類去做。這個(gè)核心類僅僅負(fù)責(zé)給出具體工廠必須實(shí)現(xiàn)的接口,而不負(fù)責(zé)哪一個(gè)產(chǎn)品類被實(shí)例化這種細(xì)節(jié),這使得工廠方法模式可以允許系統(tǒng)在不修改工廠角色的情況下引進(jìn)新產(chǎn)品。
代碼模型
public class Factory {
public static Product newInstance() {
return new ConcreteProduct();
}
}
public abstract Product {
}
public class ConcreteProduct extends Product {
public ConcreteProduct() {}
}
優(yōu)點(diǎn)
- 工廠類含有必要的判斷邏輯,可以決定在什么時(shí)候創(chuàng)建哪一個(gè)產(chǎn)品類的實(shí)例,客戶端可以免除直接創(chuàng)建產(chǎn)品對(duì)象的責(zé)任,而僅僅“消費(fèi)”產(chǎn)品;簡(jiǎn)單工廠模式通過(guò)這種做法實(shí)現(xiàn)了對(duì)責(zé)任的分割,它提供了專門的工廠類用于創(chuàng)建對(duì)象。
- 客戶端無(wú)須知道所創(chuàng)建的具體產(chǎn)品類的類名,只需要知道具體產(chǎn)品類所對(duì)應(yīng)的參數(shù)即可。
缺點(diǎn)
- 工廠類的擴(kuò)展比較困難,不符合開(kāi)閉原則
- 由于工廠類集中了所有產(chǎn)品創(chuàng)建邏輯,一旦不能正常工作,整個(gè)系統(tǒng)都要受到影響
適用環(huán)境
工廠類負(fù)責(zé)創(chuàng)建的對(duì)象比較少;客戶端只知道傳入工廠類的參數(shù),對(duì)于如何創(chuàng)建對(duì)象不關(guān)心。
應(yīng)用實(shí)例
Retrofit 中的Platform運(yùn)用了簡(jiǎn)單工廠模式
//抽象產(chǎn)品
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
//工廠
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
//具體產(chǎn)品1
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
//具體產(chǎn)品2
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
//省略部分代碼
}
原型模式
定義
用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過(guò)拷貝這些原型創(chuàng)建新的對(duì)象。
組成
- 客戶(client),客戶類提出創(chuàng)建對(duì)象的請(qǐng)求。
- 抽象原型(PhotoType),抽象原型給出所有的具體原型所需要實(shí)現(xiàn)的函數(shù)接口。
- 具體原型(ConcretePrototype),被復(fù)制的對(duì)象,實(shí)現(xiàn)了抽象原型的接口。

代碼模型
public interface Prototype extends Cloneable {
Prototype clone();
}
public class ConcretePrototype implements Prototype {
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
public class Client {
private Prototype prototype;
public void operation(Prototype example) {
Prototype p = (Prototype) example.clone();
}
}
優(yōu)點(diǎn)
性能優(yōu)良,內(nèi)存二進(jìn)制的拷貝,比直接new一個(gè)對(duì)象性能好很多。
缺點(diǎn)
構(gòu)造函數(shù)不會(huì)執(zhí)行,缺少相應(yīng)約束
適用范圍
- 資源優(yōu)化場(chǎng)景
- 一個(gè)對(duì)象多個(gè)修改者的場(chǎng)景
使用實(shí)例
Retrofit中的用于發(fā)起網(wǎng)絡(luò)請(qǐng)求的OkHttpCall就使用了原型模式,優(yōu)勢(shì)在于使用原型模式的二進(jìn)制的copy性能較好,當(dāng)由大量網(wǎng)絡(luò)請(qǐng)求時(shí),該優(yōu)勢(shì)就能更明顯的體現(xiàn)出來(lái)了。
final class OkHttpCall<T> implements Call<T> {
//省略部分代碼
@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override public OkHttpCall<T> clone() {
return new OkHttpCall<>(serviceMethod, args);
}
//省略部分代碼
}