設(shè)計(jì)模式之---工廠方法模式

簡(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è)圖片先 :###

圖片來(lái)源百度

這里寫(xiě)圖片描述

> 分析一下這個(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)####

這里寫(xiě)圖片描述

這里有兩個(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)這樣:


這里寫(xiě)圖片描述

功能就是點(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é)果####

這里寫(xiě)圖片描述
這里寫(xiě)圖片描述

可以看到功能正常


升級(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)這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容