日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

設(shè)計(jì)模式中的那些工廠(chǎng)

 頭號(hào)碼甲 2021-03-24

Intro

設(shè)計(jì)模式中有幾個(gè)工廠(chǎng)模式,聊一聊這幾個(gè)工廠(chǎng)模式的各自用法和使用示例,工廠(chǎng)模式包含簡(jiǎn)單工廠(chǎng),抽象工廠(chǎng),工廠(chǎng)方法,這些均屬于創(chuàng)建型模式,
所謂創(chuàng)建型模式,就是說(shuō)這幾個(gè)設(shè)計(jì)模式是用來(lái)創(chuàng)建對(duì)象的。

簡(jiǎn)單工廠(chǎng)

首先來(lái)說(shuō)一說(shuō),最簡(jiǎn)單的簡(jiǎn)單工廠(chǎng)

簡(jiǎn)單工廠(chǎng)模式是由一個(gè)工廠(chǎng)對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類(lèi)的實(shí)例

嚴(yán)格的來(lái)說(shuō),簡(jiǎn)單工廠(chǎng)模式是工廠(chǎng)模式家族中最簡(jiǎn)單實(shí)用的模式,但不屬于23種 GOF 設(shè)計(jì)模式之一。因?yàn)槊看我略鲱?lèi)型的時(shí)候必須修改工廠(chǎng)內(nèi)部代碼,不符合開(kāi)閉原則。

來(lái)看一個(gè)例子:

public class OperationFactory
{
    public static Operation CreateOperation(string operate)
    {
        Operation operation = null;
        switch (operate)
        {
            case "+":
                operation = new OperationAdd();
                break;

            case "-":
                operation = new OpertaionSub();
                break;

            case "*":
                operation = new OperationMul();
                break;

            case "/":
                operation = new OperationDiv();
                break;
        }
        return operation;
    }
}

這是一個(gè)簡(jiǎn)單的計(jì)算器的示例,支持簡(jiǎn)單的加減乘除操作,如果要增加一個(gè)操作的話(huà)就必須要有增加一個(gè) switch ... case 分支,需要修改 CreateOperation 方法不能滿(mǎn)足對(duì)擴(kuò)展開(kāi)放對(duì)修改關(guān)閉的開(kāi)閉原則,所以普遍地認(rèn)為簡(jiǎn)單工廠(chǎng)不屬于設(shè)計(jì)模式之一,但是我覺(jué)得有時(shí)候簡(jiǎn)單的業(yè)務(wù)處理用簡(jiǎn)單工廠(chǎng)還是比較方便的。

抽象工廠(chǎng)

抽象工廠(chǎng)模式,提供一系列相關(guān)或相互依賴(lài)對(duì)象的接口,而無(wú)需指定他們具體的類(lèi)。

實(shí)現(xiàn)抽象工作模式所需要的組件,主要部分:

  • 抽象工廠(chǎng)/抽象產(chǎn)品

  • 具體工廠(chǎng)1/具體產(chǎn)品1

  • 具體工廠(chǎng)2/具體產(chǎn)品2

  • ...

在客戶(hù)端根據(jù)不同的配置選擇不同的工廠(chǎng),例如根據(jù)配置的數(shù)據(jù)庫(kù)類(lèi)型的不同選擇使用 Access 數(shù)據(jù)庫(kù)倉(cāng)儲(chǔ)的工廠(chǎng)還是使用 SqlServer 數(shù)據(jù)庫(kù)的倉(cāng)儲(chǔ)工廠(chǎng)

示例:

IDbFactory factory = new AccessFactory();
var userRepo = factory.CreateUserRepo();
userRepo.Insert(null);
var departmentRepo = factory.CreateDepartmentRepo();

factory = new SqlServerFactory();
userRepo = factory.CreateUserRepo();
userRepo.Insert(null);

工廠(chǎng)方法

工廠(chǎng)方法模式(Factory Method)定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)。工廠(chǎng)方法使一個(gè)類(lèi)的實(shí)例化延遲到子類(lèi)。

工廠(chǎng)方法模式實(shí)現(xiàn)時(shí),客戶(hù)端需要決定實(shí)例化哪一個(gè)工廠(chǎng)來(lái)實(shí)現(xiàn)客戶(hù)端的操作,也會(huì)存在著選擇判斷的問(wèn)題,不過(guò)和簡(jiǎn)單工廠(chǎng)相比,簡(jiǎn)單工廠(chǎng)的選擇判斷是在工廠(chǎng)內(nèi)部,而工廠(chǎng)方法則將選擇判斷轉(zhuǎn)移到了客戶(hù)端。

示例:

ILeifengFactory factory = new UndergraduteFactory();
var studentLeifeng = factory.CreateLeifeng();
studentLeifeng.BuyRice();

factory = new VolunteerFactory();
var leifeng1 = factory.CreateLeifeng();
leifeng1.Sweep();

More

工廠(chǎng)模式的作用無(wú)外乎下面這四個(gè)。這也是判斷要不要使用工廠(chǎng)模式的最本質(zhì)的參考標(biāo)準(zhǔn)。

  • 封裝變化:創(chuàng)建邏輯有可能變化,封裝成工廠(chǎng)類(lèi)之后,創(chuàng)建邏輯的變更對(duì)調(diào)用者透明。

  • 代碼復(fù)用:創(chuàng)建代碼抽離到獨(dú)立的工廠(chǎng)類(lèi)之后可以復(fù)用。

  • 隔離復(fù)雜性:封裝復(fù)雜的創(chuàng)建邏輯,調(diào)用者無(wú)需了解如何創(chuàng)建對(duì)象。

  • 控制復(fù)雜度:將創(chuàng)建代碼抽離出來(lái),讓原本的函數(shù)或類(lèi)職責(zé)更單一,代碼更簡(jiǎn)潔。

工廠(chǎng)方法和抽象工廠(chǎng)的區(qū)別

工廠(chǎng)方法模式:定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)
抽象工廠(chǎng)模式:為創(chuàng)建一組相關(guān)或相互依賴(lài)的對(duì)象提供一個(gè)接口,而且無(wú)需指定他們的具體類(lèi)
區(qū)別在于產(chǎn)品,如果產(chǎn)品單一,最合適用工廠(chǎng)模式,但是如果有多個(gè)業(yè)務(wù)品種、業(yè)務(wù)分類(lèi)時(shí),通過(guò)抽象工廠(chǎng)模式產(chǎn)生需要的對(duì)象是一種非常好的解決方式。再通俗深化理解下:工廠(chǎng)模式針對(duì)的是一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu) ,抽象工廠(chǎng)模式針對(duì)的是面向多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)的。

抽象工廠(chǎng)關(guān)鍵在于產(chǎn)品之間的抽象關(guān)系,所以一般至少要兩個(gè)產(chǎn)品;工廠(chǎng)方法在于生成產(chǎn)品,不關(guān)注產(chǎn)品間的關(guān)系,所以可以只生成一個(gè)產(chǎn)品。

抽象工廠(chǎng)更像一個(gè)復(fù)雜版本的策略模式,策略模式通過(guò)更換策略來(lái)改變處理方式或者結(jié)果;而抽象工廠(chǎng)的客戶(hù)端,通過(guò)更換工廠(chǎng)而改變結(jié)果。

工廠(chǎng)方法目的是生產(chǎn)產(chǎn)品,所以能看到產(chǎn)品,而且還要使用產(chǎn)品。當(dāng)然,如果產(chǎn)品在創(chuàng)建者內(nèi)部使用,那么工廠(chǎng)方法就是為了完善創(chuàng)建者,從而可以使用創(chuàng)建者。另外創(chuàng)建者本身是不能更換所生產(chǎn)產(chǎn)品的。

抽象工廠(chǎng)的工廠(chǎng)是類(lèi);工廠(chǎng)方法的工廠(chǎng)是方法。抽象工廠(chǎng)的工廠(chǎng)類(lèi)就做一件事情生產(chǎn)產(chǎn)品。生產(chǎn)的產(chǎn)品給客戶(hù)端使用,絕不給自己用。工廠(chǎng)方法生產(chǎn)產(chǎn)品,可以給系統(tǒng)用,可以給客戶(hù)端用,也可以自己這個(gè)類(lèi)使用。自己這個(gè)類(lèi)除了這個(gè)工廠(chǎng)方法外,還可以有其他功能性的方法。

選擇的優(yōu)化

簡(jiǎn)單工廠(chǎng)因?yàn)檫x擇是在工廠(chǎng)內(nèi)部的,不符合開(kāi)閉原則,抽象工廠(chǎng)和工廠(chǎng)方法是將選擇權(quán)交給客戶(hù)端,由客戶(hù)端根據(jù)需要自己決定要實(shí)例化的工廠(chǎng)。
在實(shí)際應(yīng)用的時(shí)候大部分情況是只會(huì)使用一種工廠(chǎng),這種情況我們一般可以借助反射+配置來(lái)優(yōu)化選擇,如果使用依賴(lài)注入,可以直接注入需要的服務(wù)即可。

使用反射+配置優(yōu)化

private static readonly string AssemblyName = "AbstractFactoryPattern";
private static readonly string DbName = ConfigurationHelper.AppSetting("DbName");

public static IUserRepo CreateUserRepo()
{
    return (IUserRepo)typeof(DataAccess).Assembly.CreateInstance($"{AssemblyName}.{DbName}UserRepo");
}

public static IDepartmentRepo CreateDepartmentRepo()
{
    return (IDepartmentRepo)typeof(DataAccess).Assembly.CreateInstance($"{AssemblyName}.{DbName}DepartmentRepo");
}

使用依賴(lài)注入

依賴(lài)注入可以使得我們的代碼變得更加良好,擴(kuò)展性更強(qiáng)。

// 依賴(lài)注入
var builder = new ContainerBuilder();
builder.RegisterType<VolunteerFactory>().As<ILeifengFactory>();
builder.RegisterType<SqlServerFactory>().As<IDbFactory>();
var container = builder.Build();

var leifengFactory = container.Resolve<ILeifengFactory>();
var volunteer = leifengFactory.CreateLeifeng();
volunteer.Wash();

var dbFactory = container.Resolve<IDbFactory>();
dbFactory.CreateDepartmentRepo().CreateDepartment(null);

Reference

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多