Android中的創(chuàng)建型模式

共5中祝沸,單例模式、工廠方法模式越庇、抽象工廠模式罩锐、建造者模式、原型模式

單例模式

定義:確保某一個類的實例只有一個卤唉,而且向其他類提供這個實例涩惑。

單例模式的使用場景:某個類的創(chuàng)建需要消耗大量資源,new一個對象代價太大桑驱,如訪問IO和數(shù)據(jù)庫等資源境氢,或者避免多次創(chuàng)建該對象消耗內存過多蟀拷。

懶漢模式
public class Singleton{
    private static Singleton instance;
    
    private Singleton(){}
    
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }

}

懶漢模式是當需要改單例對象時,才初始化萍聊,與之相對的是餓漢模式问芬,靜態(tài)變量instance聲明時就初始化。

由于每一次調用getInstance()都需要同步寿桨,資源消耗大此衅。

double check Lock
public class Singleton{
    private static Singleton instance;
    
    private Singleton(){}
    
    public static Singleton getInstance(){
        if(instance == null){
            synchronize(Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

在需要時才初始化,線程安全亭螟,且對象初始化后不再進行同步鎖挡鞍。

第一次判斷null為了不必要的同步,第二層判空是在沒有其他線程進入同步塊時预烙,是否需要創(chuàng)建實例墨微。但上述示例代碼還是有問題,在代碼instance = new Singleton()處扁掸, 代碼會編譯成多條指令翘县,大致做了3件事:

1.給Singleton的實例分配內存
2.調用Singleton()構造函數(shù),初始化成員字段
3.強instance對象指向分配的內存空間(此時instance不為null)

由于java編譯器的指令執(zhí)行在不影響結果的情況下是可以亂序的谴分,所以無法保證上述2锈麸、3步驟是順序執(zhí)行的,這樣當一個線程A獲取單例時牺蹄,先執(zhí)行步驟3忘伞,步驟2還沒有執(zhí)行,就切換到線程B沙兰,由于此時instance已經不為空氓奈,所以線程B之間獲得instance,但instance的初始化還沒有完成鼎天,這樣就會造成問題舀奶。

解決DCL的失效問題就是在字段instance前面加入關鍵字volatile,該關鍵字禁止指令重排序優(yōu)化训措,確保執(zhí)行到instance = new Singleton()時的指令順序按照上述步驟1-2-3執(zhí)行伪节。

public class Singleton{
    private volatile static Singleton instance;
    
    private Singleton(){}
    
    public static Singleton getInstance(){
        if(instance == null){
            synchronize(Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
靜態(tài)內部類單例模式
public class Singleton(){
    private Singleton(){}
    
    public static Singleton(){
        return InnerSingleton.instance;
    }
    
    //靜態(tài)內部類
    private static class InnerSingleton{
        private static final Singleton instance = new Singleton();
    }
}

第一次加載Singleton時不會初始化instance,只有調用getInstance()時才初始化绩鸣,因為此時需要加載靜態(tài)內部類InnerSingleton怀大。

這種方式不僅確保線程安全,也能夠保證單例對象的唯一性呀闻,同時也延遲了對象實例化化借。

Android中的單例模式

通過context獲取的各種系統(tǒng)服務,和LayoutInflate都是采用單例模式

WindowManager wm = (WindowManager) getSystemServie(getApplication().WINDOW_SERVICE);

//ListView中getView中使用LayoutInflate
itemView = LayoutInflate.from(context).inflate(id,null);

Builder 創(chuàng)建者模式

定義:講一個復雜對象的構建與它的表示分離捡多,使得同樣的構建過程可以創(chuàng)建不同的表示蓖康。

就是說某一個對象有許多字段參數(shù)需要設置铐炫,不同的設置得到不同的結果。

public class Config{
    private int size;
    private int number;
    private String name;
    
    public Config(int size, int number, String name){
        this.size = size;
        this.number = number;
        this.name = name;
    }
    
    public void setSize(int size){
        this.size = size;
    }
    
    public void setNumber(int number){
        this.number = number;
    }
    
    public void setName(String name){
        this.name = name;
    }
}

如果只是極少數(shù)的變量需要設置蒜焊,通過構造器還是可以接受的倒信,如果變量個數(shù)特別多,構造器參數(shù)對應哪個變量就變得很難讀懂泳梆,當只需要部分參數(shù)時鳖悠,由需要重新寫一個構造方法,這是很不利于程序擴展的优妙。

public class Config{
    private int size;
    private int number;
    private String name;
    
    public int getSize() {
        return size;
    }

    public int getNumber() {
        return number;
    }

    public String getName() {
        return name;
    }
    
    public static class Builder{
        private int size;
        private int number;
        private String name;
        
        public Builder setSize(int size){
            this.size = size;
            return this;
        }
    
        public Builder setNumber(int number){
            this.number = number;
            return this;
        }
    
        public Builder setName(String name){
            this.name = name;
            return this;
        }
        
        public Config build(){
            Config config = new Config();
            config.size = size;
            config.number = number;
            config.name = name;
            return config;
        }
    }
}

當我們需要初始化Config時乘综,通過它的靜態(tài)內部類Builder進行實例化

Config.Builder builder = new Config.Builder();
Config config = builder.setName("haha")
                .setNumber(2)
                .setSize(3)
                .build();

通過返回this實現(xiàn)鏈式調用,代碼可讀性強套硼,也更好維護卡辰。

Android中的Builder模式

我們常用的提示框就采用了Builder模式

AlertDialog.Builer builder=new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon)
    .setTitle("title")
    .setMessage("message")
    .setPositiveButton("Button1", 
        new DialogInterface.OnclickListener(){
            public void onClick(DialogInterface dialog,int whichButton){
                setTitle("click");
            }    
        })
    .create()
    .show();

Notification從API11開始也采用了Builder模式

 Notification.Builder builder = new Notification.Builder(this);
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        builder.setContentIntent(pendingIntent)
                .setSmallIcon(R.drawable.ic_launcher)
                .setWhen(System.currentTimeMillis())
                .setContentText("內容")
                .setContentTitle("標題")
                .setTicker("狀態(tài)欄上顯示...")
                .setNumber(2)
                .setOngoing(true);
 //API11
  Notification notification = builder.getNotification();
  
  //API16
  Notification notification = builder.build();
  

原型模式

定義:用原型實例指定創(chuàng)建對象的種類,并通過拷貝這些原型創(chuàng)建新的對象邪意。

原型模式就是將一個對象進行克隆九妈,將一個對象的內部屬性完全復制,生成一個新的拷貝對象抄罕,被復制的實例對象就稱為原型允蚣。當一個對象的屬性過多時于颖,重新new一個對象比較復雜和消耗資源呆贿,此時就可以用原型模式。

public class CloneMode implements Cloneable {

    public String txt;

    public CloneMode(String txt) {
        this.txt = txt;
        System.out.println("----CloneMode構造函數(shù)----");
    }

    public CloneMode clone() {
        CloneMode cm;
        try {
            cm = (CloneMode) super.clone();
            cm.txt = this.txt;
            return cm;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    
    }

}

注意通過clone拷貝對象時并不會執(zhí)行構造函數(shù)森渐。還要注意的就是深拷貝淺拷貝做入,淺拷貝指的是拷貝原型對象時,并沒有將原型對象的字段重新構造同衣,而是將拷貝后的副本中的字段引用指向原型對象中的字段竟块。舉個例子:A引用B,這兩個對象指向同一個地址耐齐,當修改A時浪秘,B也會改變,B修改時埠况,A也會改變耸携。深拷貝則對于原型對象中的引用類型字段也進行拷貝,生成一個新的引用對象辕翰。將上述代碼添加一個引用類型對象夺衍,深拷貝如下:

public class CloneMode implements Cloneable {

    public int num;
    
    //引用類型對象
    public ArrayList<String> lists = new ArrayList<>();

    public CloneMode(int num) {
        this.num = num;
        System.out.println("----CloneMode構造函數(shù)----");
    }

    public CloneMode clone() {
        CloneMode cm;
        try {
            cm = (CloneMode) super.clone();
            cm.num = this.num;
            //深拷貝:引用類型對象也進行拷貝;
            cm.lists = (ArrayList<String>)this.lists.clone();
            
            //淺拷貝
            //cm.lists = this.lists;
            return cm;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    
    }

}

Android中的原型模式

Uri uri=Uri.parse("smsto:10086");
Intent shareIntent=new Intent(Intent.ACTION_SENDTO,uri);

//克隆副本
Intent intent=(Intetn)shareIntent.clone();
startActivity(intent);

工廠模式

定義:工廠模式定義一個用于創(chuàng)建對象的接口喜命,讓子類決定實例化哪個類沟沙。

下述代碼為工廠模式的通用代碼

public abstract class Product{
    public abstract void method();
} 

public class ConcreteProductA extends Prodect{
    public void method(){
        System.out.println("我是產品A!");
    }
}

public class ConcreteProductB extends Prodect{
    public void method(){
        System.out.println("我是產品B!");
    }
}
public  abstract class Factory{
    public abstract Product createProduct();
}

public class MyFactory extends Factory{

    public Product createProduct(){
        return new ConcreteProductA();
    }
}

Android中的工廠模式

其實河劝,在getSystemService方法中就是用到了工廠模式,他就是根據(jù)傳入的參數(shù)決定創(chuàng)建哪個對象矛紫,當然了赎瞎,由于返回的都是以單例模式存在的對象,因此不用new颊咬,直接把單例返回就好煎娇。

public Object getSystemService(String name) {
    if (getBaseContext() == null) {
        throw new IllegalStateException("System services not available to Activities before onCreate()");
    }
    //........
    if (WINDOW_SERVICE.equals(name)) {
         return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
    //.......
    return super.getSystemService(name);
  }

抽象工廠模式

定義:為創(chuàng)建一組相關或者是相互依賴的對象提供一個接口,而不需要指定他們的具體類贪染。

模式通用代碼:

public abstract class AbstractProductA{
    public abstract void method();
}
public abstract class AbstractProdectB{
    public abstract void method();
}

public class ConcreteProductA1 extends AbstractProductA{
    public void method(){
        System.out.println("具體產品A1的方法缓呛!");
    }
}
public class ConcreteProductA2 extends AbstractProductA{
    public void method(){
        System.out.println("具體產品A2的方法!");
    }
}
public class ConcreteProductB1 extends AbstractProductB{
    public void method(){
        System.out.println("具體產品B1的方法杭隙!");
    }
}
public class ConcreteProductB2 extends AbstractProductB{
    public void method(){
        System.out.println("具體產品B2的方法哟绊!");
    }
}

public abstract class AbstractFactory{
    public abstract AbstractProductA createProductA();

    public abstract AbstractProductB createProductB();
}

public  class ConcreteFactory1 extends AbstractFactory{
    public  AbstractProductA createProductA(){
        return new ConcreteProductA1();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB1();
    }
}

public  class ConcreteFactory2 extends AbstractFactory{
    public  AbstractProductA createProductA(){
        return new ConcreteProductA2();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB2();
    }
}

Android中的抽象工廠模式

從Framework角度來看,Activity和Service都可以看做是一個具體的工廠痰憎,oncreate()onBind()就相當于一個工廠方法票髓。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市铣耘,隨后出現(xiàn)的幾起案子洽沟,更是在濱河造成了極大的恐慌,老刑警劉巖蜗细,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裆操,死亡現(xiàn)場離奇詭異,居然都是意外死亡炉媒,警方通過查閱死者的電腦和手機踪区,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吊骤,“玉大人缎岗,你說我怎么就攤上這事“追郏” “怎么了传泊?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸭巴。 經常有香客問我眷细,道長,這世上最難降的妖魔是什么奕扣? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任薪鹦,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘池磁。我一直安慰自己奔害,他們只是感情好,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布地熄。 她就那樣靜靜地躺著华临,像睡著了一般。 火紅的嫁衣襯著肌膚如雪端考。 梳的紋絲不亂的頭發(fā)上雅潭,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機與錄音却特,去河邊找鬼扶供。 笑死,一個胖子當著我的面吹牛裂明,可吹牛的內容都是我干的椿浓。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼闽晦,長吁一口氣:“原來是場噩夢啊……” “哼扳碍!你這毒婦竟也來了?” 一聲冷哼從身側響起仙蛉,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤笋敞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后荠瘪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夯巷,經...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年巧还,在試婚紗的時候發(fā)現(xiàn)自己被綠了鞭莽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坊秸。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡麸祷,死狀恐怖,靈堂內的尸體忽然破棺而出褒搔,到底是詐尸還是另有隱情阶牍,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布星瘾,位于F島的核電站走孽,受9級特大地震影響,放射性物質發(fā)生泄漏琳状。R本人自食惡果不足惜磕瓷,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧困食,春花似錦边翁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瘩例,卻和暖如春啊胶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背垛贤。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工焰坪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人聘惦。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓琳彩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親部凑。 傳聞我的和親對象是個殘疾皇子露乏,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內容