簡(jiǎn)介
工廠方法模式定義給一個(gè):一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類(lèi)決定實(shí)例化哪個(gè)類(lèi)。
應(yīng)用場(chǎng)景:比如有幾個(gè)類(lèi),這幾個(gè)類(lèi)都有相似的功能,相似的屬性,但又不完全相同,因此它們有一個(gè)共同的父親。當(dāng)需要使用這些個(gè)子類(lèi)的時(shí)候,可以通過(guò)工廠方法模式產(chǎn)生這些個(gè)子類(lèi)的對(duì)象,而不是用 new的方式去產(chǎn)生對(duì)象。
那么問(wèn)題就又來(lái)了:通過(guò)new 的方式生成對(duì)象一句話就行,通過(guò)工廠方法模式產(chǎn)生對(duì)象雖然也不難,但是畢竟麻煩許多。那何必還要這種工廠模式呢?
工廠方法模式具有更好的封裝性,說(shuō)白了,工廠方法模式將創(chuàng)建對(duì)象的過(guò)程封裝起來(lái),需要對(duì)象是時(shí)就去工廠中提取,解耦。假設(shè)一種場(chǎng)景:
有一個(gè)類(lèi)A,如果去new的話得這樣:
A a = new A();
我在很多個(gè)地方使用到了A,我new了很多個(gè),然后突然我要改A的名字了,現(xiàn)在要new A得這樣:
B a = new B();
那我就比較麻煩了,我要把所有new A的地方都改掉。
使用工廠方法模式就比較簡(jiǎn)單了,我只需要修改創(chuàng)建A的那個(gè)工廠里面的代碼就好了。
使用
1.給個(gè)圖片先 :###
> 分析一下這個(gè)圖片:
> 有一個(gè)抽象的工廠類(lèi)Factory:是工廠類(lèi)的基類(lèi);
> 還有一個(gè)抽象的產(chǎn)品類(lèi)Product:是產(chǎn)品類(lèi)的基類(lèi);
> 具體的產(chǎn)品類(lèi)ConcreateProduct繼承基類(lèi),實(shí)現(xiàn)方法;
> 具體的工廠類(lèi)ConcreateProduct繼承基類(lèi),實(shí)現(xiàn)創(chuàng)建產(chǎn)品類(lèi)的功能;
2.代碼走起來(lái):
2.1.先看一下目錄結(jié)構(gòu)####
這里有兩個(gè)包:
- factory:存放所有工廠類(lèi)及其基類(lèi);
- product:存放所有產(chǎn)品類(lèi)及其基類(lèi);
- 還有一個(gè)Activity:用來(lái)調(diào)用上面;
2.2.然后看一下xml布局####
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="st.zlei.com.factorypattern.MainActivity"
android:orientation="vertical">
<Button
android:id="@+id/a_button"
android:text="生產(chǎn)一個(gè)A衣服產(chǎn)品"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/b_button"
android:text="生產(chǎn)一個(gè)B衣服產(chǎn)品"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/a_reflect_button"
android:text="生產(chǎn)一個(gè)A衣服產(chǎn)品_反射"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/b_reflect_button"
android:text="生產(chǎn)一個(gè)B衣服產(chǎn)品_反射"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
xml布局長(zhǎng)這樣:
功能就是點(diǎn)擊一個(gè)按鈕調(diào)用工廠類(lèi)產(chǎn)生一個(gè)產(chǎn)品實(shí)例。
2.3.主要幾個(gè)類(lèi)####
//工廠的抽象類(lèi)
//具體生產(chǎn)什么由子類(lèi)去決定
public abstract class ClothesFactory {
//父類(lèi)只有抽象的生產(chǎn)方法
//返回的也是產(chǎn)品的基類(lèi),不是具體的產(chǎn)品類(lèi)
public abstract Clothes createClothes();
}
//產(chǎn)品的抽象類(lèi)
public abstract class Clothes {
//這是產(chǎn)品應(yīng)該具有的方法,但是具體內(nèi)容是由具體產(chǎn)品來(lái)實(shí)現(xiàn)的
public abstract void method(Context context);
}
這里的產(chǎn)品指的是衣服
假設(shè)具體有2種衣服A和B
//A衣服產(chǎn)品
public class ClothesA extends Clothes {
@Override
public void method(Context context) {
Toast.makeText(context,"我是A衣服",Toast.LENGTH_LONG).show();
}
}
public class ClothesB extends Clothes {
@Override
public void method(Context context) {
Toast.makeText(context,"我是B衣服",Toast.LENGTH_LONG).show();
}
}
生產(chǎn)A,B產(chǎn)品的工廠
//A產(chǎn)品的工廠
public class ClothesAFactory extends ClothesFactory {
//返回的是A產(chǎn)品的實(shí)例
@Override
public Clothes createClothes() {
ClothesA clothesA = new ClothesA();
return clothesA;
}
}
//B產(chǎn)品的工廠
public class ClothesBFactory extends ClothesFactory {
//返回的是B產(chǎn)品實(shí)例
@Override
public Clothes createClothes() {
ClothesB clothesB = new ClothesB();
return clothesB;
}
}
使用這些工廠產(chǎn)生實(shí)例
a_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.產(chǎn)生對(duì)應(yīng)A產(chǎn)品的工廠
ClothesFactory factory = new ClothesAFactory();
//2.用工廠產(chǎn)生衣服A的對(duì)象
Clothes clothes = factory.createClothes();
//3.調(diào)用衣服A的方法
clothes.method(getApplicationContext());
}
});
b_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.產(chǎn)生對(duì)應(yīng)B產(chǎn)品的工廠
ClothesFactory factory = new ClothesBFactory();
//2.用工廠產(chǎn)生衣服B的對(duì)象
Clothes clothes = factory.createClothes();
//3.調(diào)用衣服B的方法
clothes.method(getApplicationContext());
}
});
2.4.運(yùn)行結(jié)果####
可以看到功能正常
升級(jí)版本
上面使用的是為每一個(gè)產(chǎn)品定義一個(gè)工廠,也可以用反射的方式共用一個(gè)工廠。
需要修改一下factory父類(lèi)了
//工廠的抽象類(lèi)
public abstract class ClothesFactory_reflect {
//通過(guò)反射傳進(jìn)來(lái)一個(gè)T.class,返回一個(gè)T,
//T是Clothes的子類(lèi)
//傳入一個(gè)Class類(lèi)決定哪一個(gè)產(chǎn)品類(lèi)
public abstract <T extends Clothes>T createClothes(Class<T> clz) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
具體的工廠類(lèi):
public class ClothesALLFactory extends ClothesFactory_reflect {
@Override
public <T extends Clothes> T createClothes(Class<T> clz) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//拿到產(chǎn)品的實(shí)例
Clothes clothes = (Clothes) Class.forName(clz.getName()).newInstance();
return (T) clothes;
}
}
調(diào)用:
a_reflect_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClothesFactory_reflect clothesFactory_reflect = new ClothesALLFactory();
try {
//生產(chǎn)A產(chǎn)品就傳入ClothesA.class
ClothesA clothes = clothesFactory_reflect.createClothes(ClothesA.class);
clothes.method(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
}
});
b_reflect_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClothesFactory_reflect clothesFactory_reflect = new ClothesALLFactory();
try {
//生產(chǎn)B產(chǎn)品就傳入ClothesB.class
ClothesB clothes = clothesFactory_reflect.createClothes(ClothesB.class);
clothes.method(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
運(yùn)行的結(jié)果和上面是一樣的,就不貼圖展示了.
總結(jié)
工廠模式多了一層封裝,在工廠模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶端暴露創(chuàng)建邏輯,并且是通過(guò)使用一個(gè)共同的接口來(lái)指向新創(chuàng)建的對(duì)象。
但是使用會(huì)使得類(lèi)結(jié)構(gòu)變得復(fù)雜,在比較簡(jiǎn)單的情況下,比如產(chǎn)品類(lèi)確定不會(huì)改變,并且我的需求也比較單一的情況下,我感覺(jué)完全沒(méi)有必要使用這種模式.
本文中所使用的代碼可以在本人GitHub上找到點(diǎn)這里