1.單例模式
1.1定義
確保某個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供者個實例。
1.2單例的形式
- 餓漢模式:第一次就加載,用空間換時間。
public class SingleTon {
private static SingleTon instance = new SingleTon();
//構(gòu)造函數(shù)不對外開放
private SingleTon() {
}
//通過靜態(tài)方法或枚舉進(jìn)行調(diào)用
public static SingleTon getInstance() {
return instance;
}
}
- 懶漢模式:只有在調(diào)用的時候才進(jìn)行加載,但是第一次比較慢,用時間換空間,效率不高,并且線程不安全。
public class SingleTonLH {
private static SingleTonLH instance;
//構(gòu)造函數(shù)不對外開放
private SingleTonLH() {
}
//通過靜態(tài)方法或枚舉進(jìn)行調(diào)用
public static synchronized SingleTonLH getInstance() {
if(instance == null){
instance = new SingleTonLH();
}
return instance;
}
}
- 雙重加鎖模式:使用volatile和synchronized進(jìn)行修飾。
public class SingleTonDCL {
private static volatile SingleTonDCL instance;
//構(gòu)造函數(shù)不對外開放
private SingleTonDCL() {
}
//通過靜態(tài)方法或枚舉進(jìn)行調(diào)用
public static SingleTonDCL getInstance() {
if(instance == null){
synchronized (SingleTonDCL.class) {
if (instance == null){
instance = new SingleTonDCL();
}
}
}
return instance;
}
}
- 靜態(tài)內(nèi)部類:線程安全,并且什么時候使用什么時候調(diào)用。
public class SingleTonFinal {
// 構(gòu)造函數(shù)不對外開放
private SingleTonFinal() {
}
// 通過靜態(tài)方法或枚舉進(jìn)行調(diào)用
public static SingleTonFinal getInstance() {
return SingleTonHolder.sinstance;
}
//反序列化
private Object readResolve() throws ObjectStreamException {
return SingleTonHolder.sinstance;
}
/**
* 靜態(tài)類部類
*/
private static class SingleTonHolder {
private static final SingleTonFinal sinstance = new SingleTonFinal();
}
}
- 枚舉單例:
/**
* 枚舉單例
*/
public enum SingleTonEnum {
INSTANCE;
public void dosamething(){
}
}
/**
* 調(diào)用方式
*/
class SingleTon {
private SingleTon(){
SingleTonEnum.INSTANCE.dosamething();
}
}
- 容器單例:
/**
* 容器實現(xiàn)單例模式
*/
public class SingleTonManger {
private static Map<String, Object> objMap = new HashMap<String, Object>();
// 構(gòu)造函數(shù)不對外開放
private SingleTonManger() {
}
public static void registerService(String key, Object instance) {
if (!objMap.containsKey(key)) {
objMap.put(key, instance);
}
}
public static Object getService(String key) {
return objMap.get(key);
}
}
1.3優(yōu)缺點
優(yōu)點:全局一個,節(jié)約資源。在讀文件方面,可以防止同時操作。
缺點:不易擴(kuò)展,如果要擴(kuò)展需要修改代碼,違背了開閉原則。
1.4 Android源碼對應(yīng)模式
我們經(jīng)常在Activity中通過getSystemService(String name)這個函數(shù)來獲取系統(tǒng)服務(wù),比如WMS,AMS,LayoutIlater等,這些服務(wù)都會在某一個時刻以容器單例的形式保存在應(yīng)用中。在源碼中我們知道各個服務(wù)都是保存在ContextImpl類中,在其中定義了一個SystemServiceRegistry類
final class SystemServiceRegistry {
// 存儲所有系統(tǒng)服務(wù)的集合
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =new HashMap<Class<?>, String>();
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
// 一個注冊服務(wù)的并添加到結(jié)合的方法
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
// 靜態(tài)語句塊, 只在類第一次被加載的時候調(diào)用, 保證了服務(wù)只被添加一次.
static {
// 注冊了LayoutInflate服務(wù)
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
new CachedServiceFetcher<ActivityManager>() {
@Override
public ActivityManager createService(ContextImpl ctx) {
return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
}});
/**
* 后面省略一大坨的注冊的服務(wù)代碼
**/
}
//獲得服務(wù)
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
}
2.Buider模式
2.1定義
把一個復(fù)雜的類的構(gòu)建過程和它的表示進(jìn)行分離

2.2說明
- Director:統(tǒng)一組裝過程
- Product:產(chǎn)品抽象類
- builder:抽象的builder類,規(guī)范產(chǎn)品的組建
- concreteBuilder:具體的builder類
一般實現(xiàn)
1,Product 建立抽象類
/**
* @describe 用戶抽象類
*/
public abstract class Product {
protected String name;
protected String cardID;
protected int age;
protected String address;
//定義抽象方法
public abstract void setCardID();
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
//顯示的內(nèi)容讓子類去實現(xiàn)
protected abstract String showProductInfo();
}
2.具體產(chǎn)品類
/**
* @describe product具體實現(xiàn)類
*/
public class SysProduct extends Product {
@Override
public void setCardID() {
//設(shè)置默認(rèn)ID
cardID="10086";
}
@Override
protected String showProductInfo() {
return "User [name =" + name + ",cardID=" + cardID + ",age=" + age
+ "," + "address=" + address + "]";
}
}
3.定義抽象的buider類
/**
* @describe 抽象構(gòu)造類
*/
abstract class Builder {
Product product;
public void buildName(String name) {
product.setName(name);
}
public void buildCardID() {
product.setCardID();
}
public void buildAge(int age) {
product.setAge(age);
}
public void buildAddress(String address) {
product.setAddress(address);
}
protected abstract void creat();
}
4.具體的buider實現(xiàn)類
/**
* @describe 具體的builder類
*/
public class AccountBuilder extends Builder {
SysProduct sysProduct;
@Override
protected void creat() {
sysProduct = new SysProduct();
sysProduct.setName("嘻嘻嘻");
sysProduct.setAge(20);
sysProduct.setCardID();
sysProduct.setAddress("中國");
System.out.println("Info : " + sysProduct.showProductInfo());
}
}
5.統(tǒng)一組裝類director
/**
* @describe 統(tǒng)一組裝類
*/
public class Director {
Builder mBuilder = null;
public Director(Builder builder) {
this.mBuilder = builder;
this.mBuilder.creat();
}
}
6.調(diào)用
/**
* @describe 測試類
*/
public class Test {
public static void main(String[] args) {
//統(tǒng)一組裝
new Director(new AccountBuilder());
}
}
使用鏈?zhǔn)?簡化Director
public class ChainProduct extends Product {
@Override
public void setCardID() {
// 設(shè)置默認(rèn)ID
cardID = "10086";
}
@Override
protected String showProductInfo() {
return "Info : " + "User [name =" + name + ",cardID=" + cardID + ",age=" + age
+ "," + "address=" + address + "]";
}
public static class Builder {
ChainProduct product;
public Builder() {
product = new ChainProduct();
}
public Builder buildName(String name) {
product.setName(name);
return this;
}
public Builder buildAge(int age) {
product.setAge(age);
return this;
}
public Builder buildAddress(String address) {
product.setAddress(address);
return this;
}
public Builder buildCardID() {
product.setCardID();
return this;
}
public void creat() {
System.out.println(product.showProductInfo());
}
}
}
調(diào)用方式
new ChainProduct.Builder().buildAge(20).buildAddress("中國").creat();
2.3使用場景
- 相同的方法,不同的執(zhí)行順序,產(chǎn)生不同的事件結(jié)果
- 多個部件或者零件,都可以配裝到一個對象,但是產(chǎn)生的運行結(jié)果不同
- 當(dāng)初始化一個對象特別復(fù)雜,參數(shù)多,且很多參數(shù)默認(rèn)的時候
2.4 優(yōu)缺點
優(yōu)點:封裝性良好,使用可以使客戶端不必知道產(chǎn)品內(nèi)部組成細(xì)節(jié)。建造者獨立易擴(kuò)展。
缺點:會產(chǎn)生多余的builder對象和Director對象,消耗內(nèi)存
2.5 android中使用
Director這個角色經(jīng)常會被忽略. 而直接使用一個Builder來進(jìn)行對象的封裝, 并且這個Builder通常為鏈?zhǔn)秸{(diào)用, 它的每個setter方法都會返回this自身, 比如我們常用的AlertDialog。
// 一個粗略的創(chuàng)建dialog
// 創(chuàng)建構(gòu)建者builder角色
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(android.R.drawable.sym_def_app_icon)
.setTitle("標(biāo)題")
.setMessage("message")
// 設(shè)置點擊等..
.setPositiveButton("確定", null);
// 構(gòu)建
AlertDialog alertDialog = builder.create();
// 顯示
alertDialog.show();
AlerDialog源代碼:
public class AlertDialog extends Dialog implements DialogInterface {
// AlertController 這個對象會保存Builder對象中的各個參數(shù)
private AlertController mAlert;
// 實際上操作的是上面這個變量中的屬性
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
// 省略一坨代碼如各種setter等
// Builder以內(nèi)部類的形式存在
public static class Builder {
// 1.存儲AlertDialog的各個參數(shù) 如title,icon等
private final AlertController.AlertParams P;
// 構(gòu)造函數(shù)
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
// 2. 設(shè)置參數(shù), 我們構(gòu)建的Builder設(shè)置的參數(shù)就是這些方法
public Builder setTitle(int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
// ....
// 3.構(gòu)建AlertDialog, 傳遞參數(shù)
public AlertDialog create() {
// 4.因為已經(jīng)通過builder設(shè)置了參數(shù), 接下來就可以創(chuàng)建真正需要的AlertDialog對象
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
// 5.將Builder類中的成員變量P應(yīng)用到AlertDialog類中
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
}
}
可以看到Android源碼中的AlertDialog并沒有遵循GOF設(shè)計模式中經(jīng)典的實現(xiàn)方式, 而是進(jìn)行了變種, 但卻使其使用更加的方便. 這里AlertDialog.Builder這個類同時扮演了范例中的builder,具體實現(xiàn)builder,Director的角色. 簡化了Builder設(shè)計模式, 因為模塊比較穩(wěn)定不會存在變化, 根據(jù)具體場景簡化模式, 正是體現(xiàn)了靈活運用設(shè)計模式的實例.
3.原型模式
3.1定義
用原型實例指定創(chuàng)建對象的種類,通過拷貝這個原型創(chuàng)建新的對象

3.2說明
Client:客戶端用戶
Prototype:抽象類或者接口,聲明具備clone能力。
concretePrototype:具體實現(xiàn)原型。
3.3使用場景
- 類的初始化需要消耗很多資源
- 通過new產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或者訪問權(quán)限
- 一個對象需要提供給其他對象訪問,而且其他各個調(diào)用者都需要修改其值,可以通過原型拷貝多個對象提供給調(diào)用者調(diào)用。
3.4涉及到的知識點
- 賦值:對一個對象賦值一個對象,相當(dāng)于兩個對象對原來的對象都有控制權(quán)炒作一個另一個也有變化
//繼承Cloneable類 相當(dāng)于prototype接口。wordDocument相當(dāng)于ConcreteProttype擁有賦值調(diào)用
public class WordDocument implements Cloneable {
// 文字
private String mText = "";
// 圖片
private List<String> mImages = new ArrayList<String>();
public String getText() {
return mText;
}
public void setText(String mText) {
this.mText = mText;
}
public List<String> getImages() {
return mImages;
}
public void setImages(List<String> mImages) {
this.mImages = mImages;
}
public void addImage(String img) {
this.mImages.add(img);
}
/**
* 打印文檔內(nèi)容
*/
public void showDocument() {
System.out.println("----------- Word Content Start -----------");
System.out.println("Text : " + mText);
System.out.println("Images List: ");
for (String imgName : mImages) {
System.out.println("image name : " + imgName);
}
System.out.println("----------- Word Content End -----------");
}
}

- 淺拷貝:重寫clone()方法,但是沒有對引用類型進(jìn)行拷貝,造成一個對象的引用類型發(fā)生變化另一個也會變化
//在類中添加clone 進(jìn)行淺拷貝
@Override
protected WordDocument clone() {
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
doc.mImages = this.mImages;
return doc;
} catch (Exception e) {
}
return null;
}

- 深拷貝:對引用類型再次進(jìn)行clone()
//進(jìn)行深度拷貝
ArrayList重寫了clone的方法
@SuppressWarnings("unchecked")
@Override
protected WordDocument clone() {
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
//對mImages調(diào)用clone進(jìn)行深度拷貝
doc.mImages = ((List<String>) ((ArrayList<String>) this.mImages).clone());
return doc;
} catch (Exception e) {
}
return null;
}

3.5 Android源碼對應(yīng)實現(xiàn)
- ArrayList源碼中的clone()
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
transient Object[] elementData;
private int size;
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
- Intent中實現(xiàn)
1.intent實現(xiàn)了Cloneable
public class Intent implements Parcelable, Cloneable {
}
2.對clone()重寫

沒有調(diào)用super.clone()使用了new Intent(this).當(dāng)消耗不大的時候可以使用new
4.簡單工廠模式
4.1定義
定義一個用于創(chuàng)建對象的接口,讓子類決定實例化那個類

4.2使用場景
在任何需要創(chuàng)建復(fù)雜對象的地方,都可以使用工廠模式。但是能用new創(chuàng)建對象無需使用工廠方法模式。
4.3實現(xiàn)方式
一般實現(xiàn)流程
1.定義抽象產(chǎn)品類product
/**
* @describe 抽象產(chǎn)品類
*/
public abstract class Product {
/**
* 產(chǎn)品類的抽象方法,由具體的產(chǎn)品類去實現(xiàn)
*/
public abstract void method();
}
2、具體的產(chǎn)品實現(xiàn)類
/**
* @describe 具體實現(xiàn)類A
*/
public class ConcreteProductA extends Product {
@Override
public void method() {
System.out.println("我是具體的產(chǎn)品實現(xiàn)A");
}
}
/**
* @describe 具體實現(xiàn)類B
*/
public class ConcreteProductB extends Product {
@Override
public void method() {
System.out.println("我是具體的產(chǎn)品實現(xiàn)B");
}
}
3.抽象工廠類 factory
/**
* @describe 抽象工廠類
*/
public abstract class Factory {
/**
* 抽象工廠類方法
* @return
*/
public abstract Product CreateProuct();
}
4.具體實現(xiàn)工廠類
/**
* @describe 抽象工廠類的具體實現(xiàn)方法
*/
public class ConcreteFactory extends Factory {
@Override
public Product CreateProuct() {
return new ConcreteProductA();
}
}
5.客戶端調(diào)用
/**
* @describe 調(diào)用類
*/
public class Client {
public static void main(String[] args) {
// 創(chuàng)建工廠
Factory factory = new ConcreteFactory();
// 創(chuàng)建產(chǎn)品
Product product = factory.CreateProuct();
// 調(diào)用產(chǎn)品的方法
product.method();
}
}
使用反射的方法進(jìn)行工廠方法模式
1.創(chuàng)建反射工廠抽象類
/**
* @describe 使用反射的方便調(diào)用
*/
public abstract class Factory {
public abstract <T extends Product> T createFactory(Class<T> clz);
}
2.具體的實現(xiàn)工廠類
/**
* @describe 具體的實現(xiàn)工廠類
*/
public class ConCreateFactory extends Factory{
@SuppressWarnings("unchecked")
@Override
public <T extends Product> T createFactory(Class<T> clz) {
Product p = null;
try {
p = (Product) Class.forName(clz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) p;
}
3.調(diào)用方法
/**
* @describe 調(diào)用類
*/
public class Client {
public static void main(String[] args) {
// 創(chuàng)建工廠
Factory factory = new ConCreateFactory();
// 創(chuàng)建產(chǎn)品
Product product = factory.createFactory(ConcreteProductB.class);
// 調(diào)用產(chǎn)品的方法
product.method();
}
}
}
4.3 android中的簡單工廠方法模式
onCreate是一個工廠方法
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new FrameLayout(this));
}
}
通過onCrete這個方法,我們可以構(gòu)建出任何樣式的根布局。我們在不同的Activity#onCreate()方法將設(shè)置的布局通過setContentView()函數(shù)傳遞給frameworks并顯示出來. 這不就是一個工廠模式的結(jié)構(gòu). 方法內(nèi)部可以創(chuàng)建不同的對象, 產(chǎn)生不同的實例.
service中的onBind()也可以看成工廠方法模式
5.抽象工廠模式
5.1定義
為創(chuàng)建一組相關(guān)或者相互依賴的對象提供一個接口,而不需要指定它們的具體類

5.2Android源碼對應(yīng)實現(xiàn)
抽象工廠在Android實現(xiàn)較少,基本上都可以用工廠方法模式解決。MediaPlayer底層使用的是抽象工廠模式
