android源碼中使用到的設(shè)計模式(創(chuàng)建型)

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)行分離

構(gòu)建模式

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使用場景

  1. 相同的方法,不同的執(zhí)行順序,產(chǎn)生不同的事件結(jié)果
  2. 多個部件或者零件,都可以配裝到一個對象,但是產(chǎn)生的運行結(jié)果不同
  3. 當(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使用場景

  1. 類的初始化需要消耗很多資源
  2. 通過new產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或者訪問權(quán)限
  3. 一個對象需要提供給其他對象訪問,而且其他各個調(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()重寫


Intent

沒有調(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底層使用的是抽象工廠模式

MediaPlayer
?著作權(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)容