共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()
就相當于一個工廠方法票髓。