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