個人博客:haichenyi.com。感謝關(guān)注
設(shè)計模式的分類
- 創(chuàng)建型模式,共五種:工廠方法模式祠汇、抽象工廠模式仍秤、單例模式、建造者模式可很、原型模式诗力。
- 結(jié)構(gòu)型模式,共七種:適配器模式我抠、裝飾器模式姜骡、代理模式、外觀模式屿良、橋接模式、組合模式惫周、享元模式尘惧。
- 行為型模式,共十一種:策略模式递递、模板方法模式喷橙、觀察者模式、迭代子模式登舞、責(zé)任鏈模式贰逾、命令模式、備忘錄模式菠秒、狀態(tài)模式疙剑、訪問者模式、中介者模式践叠、解釋器模式言缤。
我只講我用的多的,用的多的印象深刻禁灼,知道怎么講管挟,用的少的,不知道怎么講弄捕。只講我熟練的僻孝。
一、單例模式
單例模式守谓,我想應(yīng)該做過開發(fā)的人都用過穿铆。
懶漢式(用的時候初始化,延遲加載)
public class MySocket{
private static MySocket instance;
private MySocket(){}
public static synchronized MySocket getInstance(){
if(null == instance){
instance = new MySocket();
}
return instance;
}
}
??這里在懶漢式的單例模式中加上了同步鎖synchronized分飞,所以悴务,這是線程安全的,但是,也是因為鎖讯檐,所以造成的效率低羡疗,可以根據(jù)不同實際情況判斷是否需要加同步鎖。
餓漢式(加載類的時候直接初始化)
public class MySocket{
private static MySocket instance = new MySocket();
private MySocket(){}
public static MySocket getInstance(){
return instance;
}
}
雙重校驗鎖
public class MySocket{
private static MySocket instance;
private MySocket(){}
public static MySocket getInstance(){
if(null == instance){
synchronized(MySocket.class){
if(null == instance){
instance = new MySocket();
}
}
}
return instance;
}
}
??這里的雙重校驗鎖别洪,其實就是我這里的線程安全懶漢式的升級版本叨恨,雙重校驗鎖很多開源框架都是用的這種單例,比方說:EventBus挖垛。關(guān)于單例模式的其他變種我就不說了痒钝。單例模式的最終目的,就是全局單例痢毒,一個項目不論哪里調(diào)用這個類都是引用的同一個對象送矩。
二、工廠模式
/**
* Author: 海晨憶.
* Date: 2017/12/21
* Desc:
*/
public class FragmentFactory {
public static BaseFragment createFragment(Class<? extends BaseFragment> clz) {
return createFragment(clz, null);
}
public static BaseFragment createFragment(Class<? extends BaseFragment> clz, Bundle bundle) {
if (HomeFragment.class == clz) {
return new HomeFragment();
} else if (MyClothesFragment.class == clz) {
return new MyClothesFragment();
} else if (WardrobeStructureFragment.class == clz) {
return new WardrobeStructureFragment();
} else if (WifiFragment.class == clz) {
return new WifiFragment();
} else if (WardrobeConfigFragment.class == clz) {
return new WardrobeConfigFragment();
} else if (ShowFragment.class == clz) {
return new ShowFragment();
} else {
throw new NullPointerException("not found fragment");
}
}
public static <T extends DialogFragment> T createDialogFragment(Class<T> clz) {
return createDialogFragment(clz, null);
}
@SuppressWarnings("unchecked")
private static <T extends DialogFragment> T createDialogFragment(Class<T> clz, Bundle bundle) {
if (clz == IconDialogFragment.class) {
return (T) new IconDialogFragment();
} else if (clz == PasswordDialogFragment.class) {
return (T) PasswordDialogFragment.newInstance();
} else {
throw new NullPointerException("not found fragment");
}
}
}
??這個fragment工廠類哪替,就是我項目里面用到的栋荸。常用的工廠模式就是靜態(tài)工廠,利用static方法凭舶,我這里的工廠就是靜態(tài)工廠晌块。我們常說的工廠方法對應(yīng)的這里是什么呢?其實帅霜,工廠方法也是一個普通的方法匆背,對應(yīng)的這里就是createFragment(Class<? extends BaseFragment> clz)。工廠模式什么時候用呢身冀?在需要大量類似的數(shù)據(jù)的時候(個人觀點)钝尸,Android里面,工廠方法用的最多的就是創(chuàng)建Fragment搂根。
三蝶怔、抽象工廠模式
public interface IFragmentFactory{
BaseFragment createFragment();
}
public class HomeFactory implements IFragmentFactory{
@Override
public BaseFragment createFragment(){
return new HomeFragment();
}
}
public class WifiFragment implements IFragmentFactory{
@Override
public BaseFragment createFragment(){
return new WifiFragment();
}
}
??我把上面的靜態(tài)工廠類,改成了抽象工廠類兄墅,就是上面的代碼踢星。就是有一個工廠接口或者抽象的工廠類,然后創(chuàng)建不同的工廠類去實現(xiàn)這個接口隙咸,實現(xiàn)對應(yīng)的類沐悦,返回你需要的東西
四、建造者模式
我之前寫Luban源碼解析的時候就講過建造者模式五督,可以去看一下藏否,就在源碼解析的一開始
package com.haichenyi.mytakephoto;
/**
* Author: 海晨憶
* Date: 2018/3/6
* Desc:
*/
public class DataBean {
private String name;
private int age;
private String sex;
public DataBean(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.sex = builder.sex;
}
public static class Builder {
private String name;
private int age = 20;
private String sex = "男";
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setSex(String sex) {
this.sex = sex;
return this;
}
public DataBean build() {
return new DataBean(this);
}
}
}
??上面的代碼就是一個DataBean類,用建造者模式創(chuàng)建充包。要是還是不懂副签,你可以理解成遥椿,我們常常在寫bean類的時候,往往要寫set方法淆储,你可以理解成冠场,把set方法寫在Builder里面,在Builder里面賦好值之后本砰,在我們bean類的構(gòu)造方法里面?zhèn)鬟f過來就可以了碴裙。
五、原型模式
??這個模式我之前沒有用到過点额,研究了一下舔株,就是一個clone()方法,我個人覺得还棱,我項目中要是用载慈,也是在從服務(wù)器拿到一個list數(shù)據(jù),循環(huán)解析的時候肯定要new很多個對象珍手,這個時候娃肿,我在for循環(huán)外面new一個對象,之后珠十,在for循環(huán)里面去拷貝,重新賦值凭豪,就不用每次new一個新對象焙蹭,new新對象是耗性能的,clone是本地方法嫂伞,直接操作二進(jìn)制流孔厉,性能會好很多。
??再就是這個克隆方法帖努,也就是拷貝撰豺,分深拷貝和淺拷貝
- 淺拷貝:只會復(fù)制8基本數(shù)據(jù)類型:boolean,short拼余,float污桦,double,int匙监,long凡橱,char,byte亭姥。引用類型不會被拷貝(PS:String屬于引用類型稼钩,但是它屬于淺拷貝)
- 深拷貝:基本數(shù)據(jù)類型和引用類型都會被拷貝
淺拷貝
package com.haichenyi.mytakephoto;
import java.util.ArrayList;
/**
* Author: 海晨憶
* Date: 2018/3/7
* Desc:
*/
public class Person implements Cloneable {
private String name;
private int age;
private ArrayList<String> hobby;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public ArrayList<String> getHobby() {
return hobby;
}
@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.hobby = (ArrayList<String>) this.hobby.clone();
return person;
}
}
??上面就是一個淺拷貝的例子,實現(xiàn)Cloneable接口达罗,重寫clone()方法坝撑,前面說了只能拷貝8中數(shù)據(jù)類型,為什么這里有一個ArrayList容器呢?因為巡李,java里面很多容器他自己就實現(xiàn)了Cloneable接口抚笔,所以,就能被拷貝击儡。
深拷貝
public class Prototype implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 淺拷貝 */
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深拷貝 */
public Object deepClone() throws IOException, ClassNotFoundException {
/* 寫入當(dāng)前對象的二進(jìn)制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 讀出二進(jìn)制流產(chǎn)生的新對象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}
??上面就是一個深拷貝的例子塔沃,就是走的二進(jìn)制流。
我們在寫項目的時候阳谍,哪會去考慮深拷貝蛀柴,淺拷貝,我們關(guān)心的是只要能把我需要的東西拷貝過去就行了矫夯。所以鸽疾,我們只要把我們自己的類實現(xiàn)Cloneable接口并且實現(xiàn)clone方法,并且训貌,把這個類里面的引用類型也實現(xiàn)Cloneable接口并且實現(xiàn)clone方法即可
package com.haichenyi.mytakephoto;
import java.util.ArrayList;
/**
* Author: 海晨憶
* Date: 2018/3/7
* Desc:
*/
public class Person implements Cloneable {
private String name;
private int age;
private ArrayList<String> hobby;
private Birthday birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setHobby(ArrayList<String> hobby) {
this.hobby = hobby;
}
public void setBirthday(Birthday birthday) {
this.birthday = birthday;
}
@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.hobby = (ArrayList<String>) this.hobby.clone();
person.birthday = this.birthday.clone();
return person;
}
}
package com.haichenyi.mytakephoto;
/**
* Author: 海晨憶
* Date: 2018/3/6
* Desc:
*/
public class Birthday implements Cloneable{
private int year;
private int month;
private int day;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
protected Birthday clone() throws CloneNotSupportedException {
Birthday birthday = (Birthday) super.clone();
return birthday;
}
}
??就像上面這樣寫就可以了制肮,我們的Person類里面有一個Birthday引用類,我們的這個引用類實現(xiàn)Cloneable接口和clone()方法
PS:原型模式不會走構(gòu)造方法递沪,所以豺鼻,構(gòu)造方法里面的代碼不會被執(zhí)行