編輯:關於Android編程
這篇來介紹一下工廠方法模式(Factory Method Pattern),在實際開發過程中我們都習慣於直接使用 new 關鍵字用來創建一個對象,可是有時候對象的創造需要一系列的步驟:你可能需要計算或取得對象的初始設置;選擇生成哪個子對象實例;或在生成你需要的對象之前必須先生成一些輔助功能的對象,這個時候就需要了解該對象創建的細節,也就是說使用的地方與該對象的實現耦合在了一起,不利於擴展,為了解決這個問題就需要用到我們的工廠方法模式,它適合那些創建復雜的對象的場景,工廠方法模式也是一個使用頻率很高的設計模式。
PS:對技術感興趣的同鞋加群544645972一起交流。
工廠方法模式(Factory Method Pattern)定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,工廠方法讓類把實例化推遲到子類,這樣的設計將對象的創建封裝其來,以便於得到更松耦合,更有彈性的設計。
工廠方法模式是創建型設計模式之一,是結構較為簡單的一種模式,在我們平時的開發過程中應用也是非常的廣泛,比如 ArrayList,HashSet,與 Iterator 之間就能算是一種工廠方法。
簡單工廠模式(Simple Factory)是工廠方法模式的一種,工廠方法模式的特點總結一下:
上圖為工廠方法模式的uml類圖,幾個角色的分工也很明確,主要分為四大模塊:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCtK7ysez6c/zuaSzp73Tv9qjrMbkzqq5pLOnt723qMSjyr21xLrL0MSjrMv8tqjS5cHL0ru49rmks6fA4Mv5vt+xuLXEu/mxvtDQzqqju7b+yse+38zluaSzp6OsxuTKtc/Wwcu+38zltcTStc7xwt+8raO7yP3Kx7Ppz/Oy+sa3vdO/2qOsy/y2qNLlwcvL+dPQsvrGt7XEuau5stDQzqqju8vEyse+38zlsvrGt6OszqrKtc/Ws+nP87L6xre1xMSzuPa+38zlsvrGt7XEttTP86GjvPK1pbmks6fEo8q9us25pLOnt723qMSjyr21xMf4sfC+zdTa09q88rWluaSzp8Sjyr29q7Ppz/O5pLOnvdO/2tXiuPa9x8mruPi+q7zytfTBy6Osyse5pLOnt723qMSjyr21xNK7uPbI9buvsOaxvqGjPGJyIC8+DQqhoaGhtNPV4tbWyei8xrXEvce2yMC0y7y/vKOsuaSzp7e9t6jEo8q9ysfN6sirt/u6z8novMbUrdTytcSjrMv8vau21M/ztcS0tL2ot+LXsMbwwLSjrNLUsePT2rXDtb24/MvJ8e66z6OsuPzT0LWv0NS1xMnovMajrLb4x9K5pLOnt723qMSjyr3SwMC109qz6c/ztcS907/ao6y9q8q1wP27r7XEyM7O8b27uPjX08DgyKXN6rPJo6zT0LfHs6O6w7XEv8nAqbPk0NShow0KPHA+Jm5ic3A7PC9wPg0KPGgxIGlkPQ=="示例與源碼">示例與源碼
我們以一個簡單的玩具工廠為例,工廠中生產小孩的玩具,女生的玩具和男生的玩具,先寫一個 IToy 的抽象產品接口用來定義玩具的基本行為模式,然後實現該接口生成幾個玩具的具體產品類 ChildrenToy,MenToy 和 WomenToy 類:
IToy.class
public interface IToy {
/**
* 名字
*/
String getName();
/**
* 價格
*/
float price();
/**
* 玩
*/
void play();
}
ChildrenToy.class
public class ChildrenToy implements IToy{
@Override
public String getName() {
return "toy car";
}
@Override
public float price() {
return 10.5f;
}
@Override
public void play() {
Log.e("play", "a child is playing a toy car");
}
}
MenToy.class
public class MenToy implements IToy{
@Override
public String getName() {
return "PS4";
}
@Override
public float price() {
return 2300;
}
@Override
public void play() {
Log.e("play", "a man is playing GTA5 on ps4");
}
}
WomenToy.class
public class WomenToy implements IToy{
@Override
public String getName() {
return "plush toy";
}
@Override
public float price() {
return 200;
}
@Override
public void play() {
Log.e("play", "a woman is playing with a plush toy");
}
}
完成產品的兩個角色之後,接下來要定義工廠類的兩個角色,根據工廠方法模式和簡單工廠模式的不同,可以有兩種不同的寫法:
工廠方法模式需要先寫出一個工廠類的抽象接口來定義行為,這個時候根據實際情況我們可以分為兩種實現方式,第一種寫法會有多個 ConcreteFactory 的角色;第二種寫法只會有一個 ConcreteFactory 的角色,根據傳入的參數不同而返回不同的產品對象:
IToyCreator.class
public interface IToyCreator {
/**
* 生產玩具
*/
IToy createToy();
}
ChildrenToyCreator.class
public class ChildrenToyCreator implements IToyCreator {
private static final String TAG = "ChildrenToyCreator";
@Override
public IToy createToy() {
IToy toy = new ChildrenToy();
Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
toy.play();
return toy;
}
}
MenToyCreator.class
public class MenToyCreator implements IToyCreator {
private static final String TAG = "MenToyCreator";
@Override
public IToy createToy() {
IToy toy = new MenToy();
Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
toy.play();
return toy;
}
}
WomenToyCreator.class
public class WomenToyCreator implements IToyCreator {
private static final String TAG = "WomenToyCreator";
@Override
public IToy createToy() {
IToy toy = new WomenToy();
Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
toy.play();
return toy;
}
}
最後直接可以根據需要創建不同的 IToy 對象了,測試代碼如下:
IToyCreator toyCreator;
switch (v.getId()) {
case R.id.btn_child:
toyCreator = new ChildrenToyCreator();
toyCreator.createToy();
break;
case R.id.btn_men:
toyCreator = new MenToyCreator();
toyCreator.createToy();
break;
case R.id.btn_women:
toyCreator = new WomenToyCreator();
toyCreator.createToy();
break;
}
IToyCreator.class
public interface IToyCreator {
/**
* 生產玩具
*/
IToy createToy(Class clazz);
}
ConcreteToyCreator.class
public class ConcreteToyCreator implements IToyCreator{
private static final String TAG = "ConcreteToyCreator";
@Override
public IToy createToy(Class clazz) {
if (clazz == null){
throw new IllegalArgumentException("argument must not be null");
}
try {
IToy toy = clazz.newInstance();
Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
toy.play();
return toy;
} catch (Exception e) {
throw new UnknownError(e.getMessage());
}
}
}
這種寫法直接傳入一個 Class 對象,接著利用反射的方式進行對象的創建,可以說從某種意義上精簡了很多的工廠實現類,不用一個具體產品類就對應需要一個具體工廠類了,下面為測試代碼:
IToyCreator toyCreator;
switch (v.getId()) {
case R.id.btn_child:
toyCreator.createToy(ChildrenToy.class);
break;
case R.id.btn_men:
toyCreator.createToy(MenToy.class);
break;
case R.id.btn_women:
toyCreator.createToy(WomenToy.class);
break;
}
以上的兩種方式當然最後都能夠成功打印出正確的結果:
單個工廠實現類的方法對比前面的多個工廠實現類的方法來說更加的簡潔和動態,而且對於以後新增的產品類來說也能夠不用修改原來的代碼,符合開閉原則,但是這種寫法在某些情況下是不適用的,比如不同的 IToy 對象設置了不同的構造函數,參數都不一樣,用反射來實現就不適用了,這個時候就只能為每一個具體產品類都定義一個對應的具體工廠類了。
同樣是上面的代碼,具體工廠實現類只有一個的時候,我們還是為工廠提供了一個抽象類,那麼,如果將 IToyCreator 這個角色精簡掉,只留下 ConcreteToyCreator 的這個角色,將其中的產品生成方法設置為靜態應該也是沒問題的:
public class ToyCreator{
private static final String TAG = "ToyCreator";
public static IToy createToy(Class clazz) {
if (clazz == null){
throw new IllegalArgumentException("argument must not be null");
}
try {
IToy toy = clazz.newInstance();
Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
toy.play();
return toy;
} catch (Exception e) {
throw new UnknownError(e.getMessage());
}
}
}
像這樣的方式就稱為簡單工廠模式,上面也說過,是工廠方法模式的一個弱化版本,缺點就是失去了被子類繼承的特性,所有的壓力都集中在工廠類中,不利於維護。
總的來說,工廠方法模式是一個很好的設計模式,它遵循了一個“盡可能讓事情保持抽象”的原則,松耦合的設計原則也能夠很好的符合開閉原則,將類的實例化推遲到子類,同時也擯棄了簡單工廠模式的缺點。
但是同時工廠方法模式也有一些缺點,每次我們為工廠方法添加新的產品時就要編寫一個新的產品類,同時還要引入抽象層,當產品種類非常多時,會出現大量的與之對應的工廠對象,這必然會導致類結構的復雜化,所以對於簡單的情況下,使用工廠方法模式就需要考慮是不是有些“重”了。
https://github.com/zhaozepeng/Design-Patterns/tree/master/FactoryMethodPattern
OKHttp3是如今非常流行的Android網絡請求框架,那麼如何利用Android實現斷點續傳呢,今天寫了個Demo嘗試了一下,感覺還是有點意思准備階段我們會用到OKH
最近用上了印象筆記,覺得android 版的底部導航欄挺不錯的,好多應用裡面都有用到,想著自己動手實現一下,不多說,先上圖: 要完成這樣的效果。需要自定義ViewGrou
Android中Service的一個Demo例子Service組件是Android系統重要的一部分,網上看了代碼,很簡單,但要想熟練使用還是需要Coding。本文,主要貼
“什麼是spring aop?”,我頓時大腦浮想聯翩,我想到了事物管理、SDK、代碼監控、spring remoting,這麼多東西,我從哪裡回答