zoukankan      html  css  js  c++  java
  • 一个简单的 Generic Factory 类

    简单的工厂类的一个使用场景是, 假设有一个基类 BaseClass, 和一系列的子类 A, B, C, 工厂类根据某个参数,例如字符串 “A”, “B”, “C” 创建出相应的子类。 举例如下:

    public class Factory
    {
    public static BaseClass Create(string name)
    {
    switch (name)
    {
    case "A": return new A();
    case "B": return new B();
    case "C": return new C();
    default: throw new ArgumentException("Wrong Name");
    }
    }
    }

    这里的一个问题是, 当子类增加或减少时, Factory 类 需要相应的改动。 有没有办法可以只是改动子类本身, 而不用修改Factory类呢, 当然有,这里我举一个简单的实现。

    基本思想是在每个子类上附加一个 Attribute, 定义如下:

    [AttributeUsage(AttributeTargets.Class)]
    public class FactoryKeyAttribute : Attribute
    {
    public object Key { get; set; }
    }

    假设我们有基类和子类实现如下

    public abstract class BaseClass {}

    [FactoryKey(Key = "Standard")]
    public class Standard : BaseClass {}

    [FactoryKey(Key = "Enterprise")]
    public class Enterprise : BaseClass {}

    [FactoryKey(Key = "Lite")]
    public class Lite : BaseClass {}

    假设这些类都在同一个 Assembly中 (对于不在同一个Assembly的,实现会稍微复杂些)工厂类需要预先加载 Key => Type 的Mapping, 然后根据Key创建不同的实例, 实现如下:

    public class Factory<TKey, TBaseClass>
    {
    private static readonly IDictionary<TKey, Type> TypeDict = Init();
    private static IDictionary<TKey, Type> Init()
    {
    var dict = from type in Assembly.GetExecutingAssembly().GetTypes()
    let key = (FactoryKeyAttribute)Attribute.GetCustomAttribute(type, typeof(FactoryKeyAttribute))
    where key != null && typeof(TBaseClass).IsAssignableFrom(type)
    select new { Key = key, Value = type };

    return dict.ToDictionary(kvp => (TKey)kvp.Key.Key, kvp => kvp.Value);
    }

    public static TBaseClass CreateInstance(TKey key)
    {
    Type type;
    if (TypeDict.TryGetValue(key, out type))
    {
    return (TBaseClass)Activator.CreateInstance(type);
    }

    throw new ArgumentException("Incorrect Key!");
    }
    }

    使用方法也很简单:

    BaseClass s = Factory<string, BaseClass>.CreateInstance("Standard");
    BaseClass l = Factory<string, BaseClass>.CreateInstance("Lite");
    BaseClass e = Factory<string, BaseClass>.CreateInstance("Enterprise");

    对于其他类型的Key,比如 Enum, 或其他类型的基类, 改变Factory 的类型参数即可。

  • 相关阅读:
    laravel报错1071 Specified key was too long; max key length is 1000 bytes
    【laravel】Eloquent 模型事件和监听方式
    angular使用forRoot() 注册单一实例服务
    js判断电脑是windows系统还是mac系统
    扁平数据根据`parentId`生成树结构
    页面滚动到指定元素区域
    js简洁模式代码
    简单git使用命令
    图片懒加载 echo.js
    页面图片预加载与懒加载
  • 原文地址:https://www.cnblogs.com/smallfa/p/1641210.html
Copyright © 2011-2022 走看看