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

分享

模式:工程化實(shí)現(xiàn)及擴(kuò)展——工廠模式

 Coder編程 2020-06-30

相比較傳統(tǒng)的工廠模式IFactory/Concrete Factory會(huì)反復(fù)引用并編譯代碼
但是作為開(kāi)發(fā)人員,我們更希望的是少修改代碼,盡量從配置著手也就是設(shè)計(jì)模式的根本原則之一:開(kāi)放封閉原則。如果我要增加新的產(chǎn)品,那么修改就比較大了,對(duì)于業(yè)務(wù)來(lái)講還是可以接受的。但是如果可以做到不修改代碼是最好的。上一份工作中,我印象最深的一句話就是我上司對(duì)我說(shuō)的"能不改代碼就別改,能寫進(jìn)配置里的就寫到配置里"。因此我們將要增加的工廠類寫到配置里面。如此,新的產(chǎn)品類型和工廠類型即便在系統(tǒng)上線后仍可以通過(guò)修改配置文件的方式不斷補(bǔ)充。但是,還有一個(gè)問(wèn)題,我們?nèi)匀恍枰獮槊?quot;類"抽象產(chǎn)品定制特定的工廠接口并實(shí)現(xiàn)之,也就是"多頭管理"問(wèn)題。泛型可以用來(lái)解決這個(gè)問(wèn)題,我們定義一個(gè)泛型工廠即可。代碼如下:

/// <summary>
/// 工廠接口定義
/// </summary>
/// <remarks>
/// TTarget: 抽象產(chǎn)品類型
/// TSource: 具體產(chǎn)品類型
/// </remarks>
public interface IFactory
{
    #region config and register type mapping

    /// <summary>
    /// 如果需要同時(shí)加載配置文件中定義的映射關(guān)系,可以按照SRP的原則定義獨(dú)立的配置類型。
    /// 由該配置類型調(diào)用這兩個(gè)接口為Factory加載配置信息
    /// </summary>

    IFactory RegisterType<TTarget, TSource>();  // 注入產(chǎn)品
    IFactory RegisterType<TTarget, TSource>(string name);   // 注入產(chǎn)品

    #endregion

    #region factory method

    TTarget Create<TTarget>();
    TTarget Create<TTarget>(string name);

    #endregion
}

/// <summary>
/// 充當(dāng) 依賴注入 的角色
/// </summary>
public sealed class TypeRegistry
{
    /// <summary>
    /// default name in type mappings
    /// </summary>
    readonly string DefaultName = Guid.NewGuid().ToString();

    /// <summary>
    /// Type        :   TTarget, 抽象產(chǎn)品類型
    /// IDictionary<string ,Type>
    ///     string  :   name
    ///     Type    :   TSource, 具體產(chǎn)品類型
    /// </summary>
    IDictionary<Type, IDictionary<string, Type>> registry =
        new Dictionary<Type, IDictionary<string, Type>>();

    public void RegisterType(Type targetType, Type sourceType)
    {
        RegisterType(targetType, sourceType, DefaultName);
    }

    public void RegisterType(Type targetType, Type sourceType, string name)
    {
        if(targetType == null) throw new ArgumentNullException("targetType");
        if(sourceType == null) throw new ArgumentNullException("sourceType");
        if(string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

        if (!registry.TryGetValue(targetType, out IDictionary<string, Type> subDictionary))
        {
            subDictionary = new Dictionary<string, Type>
            {
                { name, sourceType }
            };
            registry.Add(targetType, subDictionary);
        }
        else
        {
            if (subDictionary.ContainsKey(name))
                throw new Exception($"{name}重復(fù)");
            subDictionary.Add(name, sourceType);
        }
    }

    public Type this[Type targetType, string name]
    {
        get
        {
            if (targetType == null) throw new ArgumentNullException("targetType");
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
            if (registry.Count() == 0)
                return null;

            return 
                (registry.Where(x => x.Key == targetType)).FirstOrDefault().Value
                    .Where(x => string.Equals(name, x.Key)).FirstOrDefault().Value;
        }
    }

    public Type this[Type targetType]
    {
        get { return this[targetType, DefaultName]; }
    }
}

public class Factory : IFactory
{
    protected TypeRegistry registry = new TypeRegistry();

    #region IFactory Members

    public IFactory RegisterType<TTarget, TSource>()
    {
        registry.RegisterType(typeof(TTarget), typeof(TSource));
        return this;
    }

    public IFactory RegisterType<TTarget, TSource>(string name)
    {
        registry.RegisterType(typeof(TTarget), typeof(TSource), name);
        return this;
    }

    public TTarget Create<TTarget>()
    {
        return (TTarget)Activator.CreateInstance(registry[typeof(TTarget)]);
    }

    public TTarget Create<TTarget>(string name)
    {
        return (TTarget)Activator.CreateInstance(registry[typeof(TTarget), name]);
    }

    #endregion
}

上面的示例表明新的工廠類型不僅可以完成經(jīng)典工廠方法模式所希望實(shí)現(xiàn)的各項(xiàng)要求,也滿足抽象工廠的要求,同時(shí)他可以作為整個(gè)項(xiàng)目一個(gè)獨(dú)立的而且是唯一的工廠入口,供項(xiàng)目中各子系統(tǒng)訪問(wèn)和使用。原因在于它的底層將工廠接口與抽象產(chǎn)品類型的依賴關(guān)系變成基于CLR"萬(wàn)能工廠"類型Activator基于參數(shù)Type的構(gòu)造。
工廠管理的是其內(nèi)的產(chǎn)品。我們的工廠接口IFactory有兩個(gè)功能,一個(gè)是往工廠中注入產(chǎn)品,一個(gè)是創(chuàng)建指定產(chǎn)品的實(shí)例。借助RegisterType將配置文件中定義的類型映射方希加載到新的具體工廠類型中,也就是重載函數(shù)中的參數(shù)(name)。我們通過(guò)字典Dictionary來(lái)管理維護(hù)工廠內(nèi)的產(chǎn)品,將抽象產(chǎn)品也就是接口或是抽象類作為key,要考慮到同一接口可以有多個(gè)不同的實(shí)現(xiàn),因此我們?cè)倬S護(hù)一個(gè)實(shí)現(xiàn)類的字典,使用一個(gè)唯一的標(biāo)識(shí)作為key就行,value就是實(shí)現(xiàn)類。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(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)遵守用戶 評(píng)論公約

    類似文章 更多