Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# GoF工厂的命名约定?_C#_Factory_Abstract_Factory Pattern - Fatal编程技术网

C# GoF工厂的命名约定?

C# GoF工厂的命名约定?,c#,factory,abstract,factory-pattern,C#,Factory,Abstract,Factory Pattern,此模式使用抽象工厂,然后使用工厂的实现 我确信这两个类有一个标准的命名约定,但我不知道它是什么 例如: 公共抽象类ChocolateFactory{} 公共类MyChocolateFactory{}:ChocolateFactory 这里的标准惯例是什么 我在考虑ChocolateFactoryBase或ConcreteChocolateFactory,但可能还有其他东西(很像Enums,往往以Enum作为后缀,例如PetTypeEnum,这样您就可以PetTypeEnum-PetType; 希

此模式使用抽象工厂,然后使用工厂的实现

我确信这两个类有一个标准的命名约定,但我不知道它是什么

例如:

公共抽象类ChocolateFactory{}

公共类MyChocolateFactory{}:ChocolateFactory

这里的标准惯例是什么

我在考虑ChocolateFactoryBase或ConcreteChocolateFactory,但可能还有其他东西(很像Enums,往往以Enum作为后缀,例如
PetTypeEnum
,这样您就可以
PetTypeEnum-PetType;


希望这不是主观的。

我不知道这里有什么约定,但我认为这在很大程度上取决于具体情况。我只在依赖注入secenarios中使用AbstractFactory,我想在运行时创建类型,我必须提供一个抽象

  • “抽象”部分可以是接口->约定为I名称
  • 您的基类应该描述其实现的一个“常见”事物,信息存在于上下文中:如果在您的上下文中巧克力工厂可以是一个“抽象”概念,那么实现(应该描述具体事物(MyChocketFactory不是一个好名字))应该显示它们的(is)关系,但也是具体的用例
  • 关于您的评论:如果不需要任何其他工厂实现,就不要使用抽象工厂,这只是为了将来可能的用例;)

  • 您可以使用以下内容:

    // general interface for abstract factory (this is optional)
    public abstract class AbstractFactory { };
    
    // interface that uses a type of factory and produce abstract product
    public abstract class AbstractChocolateFactory : AbstractFactory  { };
    
    // family of concrete factories that produce concrete products
    public class NestleChocolateFactory { } : AbstractChocolateFactory 
    
    public class SwissChocolateFactory { } : AbstractChocolateFactory 
    

    这只是一个简单的概念,但使用抽象工厂模式的实现完全取决于您的具体任务。

    问题和答案

    好的,这个问题从抽象工厂的命名问题开始。作为经验法则,始终使用“正式”名称(如工厂、装饰商等)和具体实施的描述(如Snickers、Mars、Motif Widget等)

    因此,基本上,您创建了一个
    MSSQLConnection
    ,这是您正在描述的具体内容,以及
    Factory
    ,这意味着它遵循Factory模式的特征

    好的,到目前为止,关于命名和原始问题。现在来看看酷的东西。讨论了在C#中实现抽象工厂的最佳方法,这是一个不同的主题。我在C#中实现所有设计模式方面做了很多工作,为此我将在这里分享一些关于工厂的细节。下面是:

    抽象工厂和工厂

    抽象工厂基本上是基类或接口与具体实现的组合。如果共享大量代码,则需要基类;如果不共享,则需要接口

    我通常区分“工厂”和“抽象工厂”。工厂是创建对象(特定类型)的东西,“抽象工厂”是创建任意类型对象的东西。因此,抽象工厂的实现就是工厂。这与下一条信息有关

    工厂模式

    支持RTTI的语言能够实现工厂模式。工厂模式是创建对象的东西。最简单的实现是只包含创建对象的方法的类,例如:

    // ...
    
    public void CreateConnection()
    {
        return new SqlConnection();
    }
    
    // ...
    
    你通常用它来抽象事物。例如,HTML解析器中生成XML节点的东西会基于HTML标记创建特定类型的节点

    工厂通常根据运行时信息做出决策。因此,可以将工厂模式概括为实现以下功能:

    public T Create(string name) 
    {
        // lookup constructor, invoke.
    }
    
    使用RTTI为每个名称存储
    类型
    ,很容易创建一个通用的工厂模式。查找名称,使用反射创建对象。完成了

    哦,作为奖励,你必须编写比手工制作所有工厂更少的代码。因为所有的实现都是相同的,所以您最好将它放在基类中,并在静态构造函数中填充字典

    概括抽象工厂

    抽象工厂基本上是以与工厂模式相同的方式创建对象的工厂集合。唯一共享的是接口(例如,创建或使用继承创建抽象)

    这个实现非常简单,所以我就到此为止

    分离工厂和类型

    让我们回到GoF的例子。他们谈论的是一个
    工厂
    和一个
    工厂
    。在未来,我们将遇到另一个UI thingie,我们将需要一个
    ASPNETFactory
    SilverlightFactory
    。然而,未来是未知的,如果我们不需要的话,我们宁愿不发送我们的旧DLL——毕竟,这是不灵活的

    如果我们想给工厂增加一种新方法,第二个问题就会出现。因此,这样做将涉及改变所有工厂。你可能已经猜到了,我不想在多个地方改变这一点

    幸运的是,我们可以解决这两个问题。接口是相同的(甚至可以通用化),因此我们可以在运行时简单地向工厂添加新功能

    我们可以使用一个属性来告诉类它应该由某个工厂具体化,而不是告诉工厂要创建什么对象。我们还可以在加载程序集的过程中扫描所有类型,因此,如果加载了程序集,我们只需动态构建新工厂即可

    为此我牺牲的是编译时检查,但因为工厂模式通常使用运行时信息,所以这不一定是问题

    总而言之,我的工厂代码如下:

    /// <summary>
    /// This attribute is used to tag classes, enabling them to be constructed by a Factory class. See the <see cref="Factory{Key,Intf}"/> 
    /// class for details.
    /// </summary>
    /// <remarks>
    /// <para>
    /// It is okay to mark classes with multiple FactoryClass attributes, even when using different keys or different factories.
    /// </para>
    /// </remarks>
    /// <seealso cref="Factory{Key,Intf}"/>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    public class FactoryClassAttribute : Attribute
    {
        /// <summary>
        /// This marks a class as eligible for construction by the specified factory type.
        /// </summary>
        /// <example>
        /// [FactoryClass("ScrollBar", typeof(MotifFactory))]
        /// public class MotifScrollBar : IControl { }
        /// </example>
        /// <param name="key">The key used to construct the object</param>
        /// <param name="factoryType">The type of the factory class</param>
        public FactoryClassAttribute(object key, Type factoryType)
        {
            if ((factoryType.IsGenericType &&
                 factoryType.GetGenericTypeDefinition() == typeof(Factory<,>)) ||
                factoryType.IsAbstract || 
                factoryType.IsInterface)
            {
                throw new NotSupportedException("Incorrect factory type: you cannot use GenericFactory or an abstract type as factory.");
            }
            this.Key = key;
            this.FactoryType = factoryType;
        }
    
        /// <summary>
        /// The key used to construct the object when calling the <see cref="Factory{Key,Intf}.Create(Key)"/> method.
        /// </summary>
        public object Key { get; private set; }
    
        /// <summary>
        /// The type of the factory class
        /// </summary>
        public Type FactoryType { get; private set; }
    }
    
    /// <summary>
    /// Provides an interface for creating related or dependent objects.
    /// </summary>
    /// <remarks>
    /// <para>
    /// This class is an implementation of the Factory pattern. Your factory class should inherit this Factory class and 
    /// you should use the [<see cref="FactoryClassAttribute"/>] attribute on the objects that are created by the factory.
    /// The implementation assumes all created objects share the same constructor signature (which is not checked by the Factory). 
    /// All implementations also share the same <typeparamref name="Intf"/> type and are stored by key. During runtime, you can 
    /// use the Factory class implementation to build objects of the correct type.
    /// </para>
    /// <para>
    /// The Abstract Factory pattern can be implemented by adding a base Factory class with multiple factory classes that inherit from 
    /// the base class and are used for registration. (See below for a complete code example).
    /// </para>
    /// <para>
    /// Implementation of the Strategy pattern can be done by using the Factory pattern and making the <typeparamref name="Intf"/>
    /// implementations algorithms. When using the Strategy pattern, you still need to have some logic that picks when to use which key.
    /// In some cases it can be useful to use the Factory overload with the type conversion to map keys on other keys. When implementing 
    /// the strategy pattern, it is possible to use this overload to determine which algorithm to use.
    /// </para>
    /// </remarks>
    /// <typeparam name="Key">The type of the key to use for looking up the correct object type</typeparam>
    /// <typeparam name="Intf">The base interface that all classes created by the Factory share</typeparam>
    /// <remarks>
    /// The factory class automatically hooks to all loaded assemblies by the current AppDomain. All classes tagged with the FactoryClass
    /// are automatically registered.
    /// </remarks>
    /// <example>
    /// <code lang="c#">
    /// // Create the scrollbar and register it to the factory of the Motif system
    /// [FactoryClass("ScrollBar", typeof(MotifFactory))]
    /// public class MotifScrollBar : IControl { }
    /// 
    /// // [...] add other classes tagged with the FactoryClass attribute here...
    ///
    /// public abstract class WidgetFactory : Factory&lt;string, IControl&gt;
    /// {
    ///     public IControl CreateScrollBar() { return Create("ScrollBar") as IScrollBar; }
    /// }
    ///
    /// public class MotifFactory : WidgetFactory { }
    /// public class PMFactory : WidgetFactory { }
    ///
    /// // [...] use the factory to create a scrollbar
    /// 
    /// WidgetFactory widgetFactory = new MotifFactory();
    /// var scrollbar = widgetFactory.CreateScrollBar(); // this is a MotifScrollbar intance
    /// </code>
    /// </example>
    public abstract class Factory<Key, Intf> : IFactory<Key, Intf>
        where Intf : class
    {
        /// <summary>
        /// Creates a factory by mapping the keys of the create method to the keys in the FactoryClass attributes.
        /// </summary>
        protected Factory() : this((a) => (a)) { }
    
        /// <summary>
        /// Creates a factory by using a custom mapping function that defines the mapping of keys from the Create 
        /// method, to the keys in the FactoryClass attributes.
        /// </summary>
        /// <param name="typeConversion">A function that maps keys passed to <see cref="Create(Key)"/> to keys used with [<see cref="FactoryClassAttribute"/>]</param>
        protected Factory(Func<Key, object> typeConversion)
        {
            this.typeConversion = typeConversion;
        }
    
        private Func<Key, object> typeConversion;
        private static object lockObject = new object();
        private static Dictionary<Type, Dictionary<object, Type>> dict = null;
    
        /// <summary>
        /// Creates an instance a class registered with the <see cref="FactoryClassAttribute"/> attribute by looking up the key.
        /// </summary>
        /// <param name="key">The key used to lookup the attribute. The key is first converted using the typeConversion function passed 
        /// to the constructor if this was defined.</param>
        /// <returns>An instance of the factory class</returns>
        public virtual Intf Create(Key key)
        {
            Dictionary<Type, Dictionary<object, Type>> dict = Init();
            Dictionary<object, Type> factoryDict;
            if (dict.TryGetValue(this.GetType(), out factoryDict))
            {
                Type t;
                return (factoryDict.TryGetValue(typeConversion(key), out t)) ? (Intf)Activator.CreateInstance(t) : null;
            }
            return null;
        }
    
        /// <summary>
        /// Creates an instance a class registered with the <see cref="FactoryClassAttribute"/> attribute by looking up the key.
        /// </summary>
        /// <param name="key">The key used to lookup the attribute. The key is first converted using the typeConversion function passed 
        /// to the constructor if this was defined.</param>
        /// <param name="constructorParameters">Additional parameters that have to be passed to the constructor</param>
        /// <returns>An instance of the factory class</returns>
        public virtual Intf Create(Key key, params object[] constructorParameters)
        {
            Dictionary<Type, Dictionary<object, Type>> dict = Init();
            Dictionary<object, Type> factoryDict;
            if (dict.TryGetValue(this.GetType(), out factoryDict))
            {
                Type t;
                return (factoryDict.TryGetValue(typeConversion(key), out t)) ? (Intf)Activator.CreateInstance(t, constructorParameters) : null;
            }
            return null;
        }
    
        /// <summary>
        /// Enumerates all registered attribute keys. No transformation is done here.
        /// </summary>
        /// <returns>All keys currently known to this factory</returns>
        public virtual IEnumerable<Key> EnumerateKeys()
        {
            Dictionary<Type, Dictionary<object, Type>> dict = Init();
            Dictionary<object, Type> factoryDict;
            if (dict.TryGetValue(this.GetType(), out factoryDict))
            {
                foreach (object key in factoryDict.Keys)
                {
                    yield return (Key)key;
                }
            }
        }
    
        private void TryHook()
        {
            AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(NewAssemblyLoaded);
        }
    
        private Dictionary<Type, Dictionary<object, Type>> Init()
        {
            Dictionary<Type, Dictionary<object, Type>> d = dict;
            if (d == null)
            {
                lock (lockObject)
                {
                    if (dict == null)
                    {
                        try
                        {
                            TryHook();
                        }
                        catch (Exception) { } // Not available in this security mode. You're probably using shared hosting
    
                        ScanTypes();
                    }
                    d = dict;
                }
            }
            return d;
        }
    
        private void ScanTypes()
        {
            Dictionary<Type, Dictionary<object, Type>> classDict = new Dictionary<Type, Dictionary<object, Type>>();
            foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
            {
                AddAssemblyTypes(classDict, ass);
            }
            dict = classDict;
        }
    
        private void AddAssemblyTypes(Dictionary<Type, Dictionary<object, Type>> classDict, Assembly ass)
        {
            try
            {
                foreach (Type t in ass.GetTypes())
                {
                    if (t.IsClass && !t.IsAbstract &&
                        typeof(Intf).IsAssignableFrom(t))
                    {
                        object[] fca = t.GetCustomAttributes(typeof(FactoryClassAttribute), false);
                        foreach (FactoryClassAttribute f in fca)
                        {
                            if (!(f.Key is Key))
                            {
                                throw new InvalidCastException(string.Format("Cannot cast key of factory object {0} to {1}", t.FullName, typeof(Key).FullName));
                            }
                            Dictionary<object, Type> keyDict;
                            if (!classDict.TryGetValue(f.FactoryType, out keyDict))
                            {
                                keyDict = new Dictionary<object, Type>();
                                classDict.Add(f.FactoryType, keyDict);
                            }
                            keyDict.Add(f.Key, t);
                        }
                    }
                }
            }
            catch (ReflectionTypeLoadException) { } // An assembly we cannot process. That also means we cannot use it.
        }
    
        private void NewAssemblyLoaded(object sender, AssemblyLoadEventArgs args)
        {
            lock (lockObject)
            {
                // Make sure new 'create' invokes wait till we're done updating the factory
                Dictionary<Type, Dictionary<object, Type>> classDict = new Dictionary<Type, Dictionary<object, Type>>(dict);
                dict = null;
                Thread.MemoryBarrier();
    
                AddAssemblyTypes(classDict, args.LoadedAssembly);
                dict = classDict;
            }
        }
    }
    
    //
    ///此属性用于标记类,使它们能够由工厂类构造。硒