命名约定GoF的工厂? [英] Naming convention for GoF Factory?

查看:118
本文介绍了命名约定GoF的工厂?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此模式使用一个抽象工厂,然后在工厂的实现。

This pattern uses an abstract factory, and then an implementation of the factory.

我相信有这两个类标准命名约定,但我不。'知道它是什么

I am sure there is a standard naming convention for these two classes, but I don't know what it is.

例如:

公共抽象类ChocolateFactory {};

公共类MyChocolateFactory {}:ChocolateFactory

什么是标准约定在这里?

What's the standard convention here?

我想无论是ChocolateFactoryBase,或ConcreteChocolateFactory,但也许还有别的东西(很像枚举倾向于与枚举为后缀,例如, PetTypeEnum ,这样就可以做到 PetTypeEnum PetType;

I'm thinking either ChocolateFactoryBase, or ConcreteChocolateFactory, but perhaps there is something else (much like Enums tend to be suffixed with Enum, e.g. PetTypeEnum so that you can do PetTypeEnum PetType;

但愿这不是主观的。

推荐答案

的问题与答案

OK,这个问题开始与抽象的工厂命名的问题。作为一个经验法则,始终使用正式的名字,你在做什么(例如厂,装饰等),具体实施的说明(如士力架,火星,MotifWidget,等等等等)。

OK, this question started with a naming question of Abstract factories. As a rule of thumb, always use the 'formal' name what you're doing (e.g. Factory, Decorator, etc) and a description of the concrete implementation (e.g. Snickers, Mars, MotifWidget, etc, etc).

因此​​,基本上,你创建一个 MSSQLConnection 这是您所描述的具体的东西,而工厂,这意味着它遵循工厂模式的特点。

So basically, you create a MSSQLConnection which is the concrete thing you're describing, and Factory which means it follows the characteristics of the factory pattern.

确定,到目前为止命名和原来的问题。现在的很酷的东西。讨论去实现在C#中,这是一个不同的主题抽象工厂的最佳途径。我做了关于实施在C#中所有的设计模式,为此,我将分享工厂的一些细节颇这里的一些工作。这里所说:

OK, so far for naming and the original question. Now for the cool stuff. The discussion goes to the best way to implement abstract factories in C#, which is a different topic. I did quite some work on implementing all design patterns in C#, for which I'll share some details on Factories here. Here goes:

抽象工厂和工厂

摘要工厂基本上都是组合的基类或接口,以及一个具体实现。基类是你想要什么,如果你,如果你不共享很多代码,接口。

Abstract factories are basically a combination of a base class or interface, and a concrete implementation. A base class is what you want if you share a lot of code, an interface if you don't.

我通常做的工厂和抽象的区分工厂。一个工厂是创建对象(某种类型的),一个抽象工厂是创建任意类型的对象,一件事一件事。因此,可以得出一个的抽象工厂的的实现是一个的工厂的。这是有关下一个一块信息。

I usually make a distinction between 'factories' and 'abstract factories'. A factory is a thing that creates objects (of a certain type), an 'abstract factory' is a thing that creates objects of arbitrary types. As such, it follows that an implementation of an abstract factory is a factory. This is relevant for the next piece of info.

工厂模式

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

Languages that support RTTI are able to implement the factory pattern. A factory pattern is a thing that creates objects. The most trivial implementation is a class that only contains methods that create objects, e.g.:

// ...

public void CreateConnection()
{
    return new SqlConnection();
}

// ...

您平时使用这种抽象的东西了。例如,在一个HTML解析器生成XML节点的事情创建一个基于HTML标签的特定类型的节点。

You usually use this to abstract things away. For example, the thing in a HTML parser that generates XML nodes creates a node of a certain type based on the HTML tag.

工厂经常会根据运行时信息的决定。因此,可以概括工厂模式来实现这样的:

Factories often make decisions based on runtime information. It is therefore possible to generalize the Factory pattern to implement something like:

public T Create(string name) 
{
    // lookup constructor, invoke.
}



这是很容易创建使用RTTI一个存储<$广义工厂模式C $ C>键入为每名。查找名称,创建使用反射的对象。完成。

It's pretty easy to create a generalized factory pattern using RTTI that stores a Type for each name. Lookup the name, create the object using reflection. Done.

呵呵,并作为奖励,你必须写比手工制作的所有工厂的方式更少的代码。由于所有的实现都是一样的,你可能也只是把它放在一个基类和静态构造函数填补了词典。

Oh and as a bonus you have to write way less code than making all the factories by hand. Because all implementations are the same, you might as well just put it in a base class and fill the Dictionary in a static constructor.

泛化抽象工厂

摘要工厂基本上都是创建对象的方式与工厂模式相同的工厂的集合。这是共享的唯一的事情是接口(例如创建,也可以使用继承来创建一个抽象)。

Abstract factories are basically collections of factories that create objects the same way as a Factory pattern. The only thing that's shared is the interface (e.g. Create or you can use inheritance to create an abstraction).

的实现并不重要,所以我就留在这一点。

The implementation is quite trivial, so I'll just leave it at that.

去耦厂家,不同型号

让我们回到GoF的例子。他们谈论一个 MotifFactory PMFactory 。在未来,我们还会遇到另一个UI的thingie,我们需要一个 ASPNETFactory SilverlightFactory 。不过,未来是未知的,如果我们不需要,我们宁愿不出货我们的老DLL的 - 毕竟,这是不灵活。

Let's go back to the GoF example. They talk about a MotifFactory and a PMFactory. In the future we will encounter yet another UI thingie and we'll need an ASPNETFactory or a SilverlightFactory. However, the future is unknown and we'd rather not ship our old DLL's if we don't need to - after all, that's not flexible.

第二个问题边棱,​​如果我们想要一个新的方法添加到我们的工厂。由此可见,这样做会涉及到更改所有工厂。正如你可能已经猜到了,我不想在多个地方改变这一点。

A second problem arrises if we want to add a new method to our factory. It follows that doing this will involve changing all factories. As you might have guessed, I don't want to change this in multiple places.

幸运的是,我们可以解决这两个问题。该接口是相同的(它甚至可以广义),所以我们可以简单的在运行时添加新的功能,我们的工厂。

Fortunately we can solve both these issues. The interface is the same (and it can even be generalized) so we can simply add new features to our factory at runtime.

不是告诉工厂哪些对象创建的,我们可以通过的某工厂使用属性告诉类,应该物化的 。我们也可以装配的负载时扫描所有类型,因此,如果一个程序集被加载,我们可以简单地在即时建设新工厂。

Instead of telling the factory what objects to create, we can use an attribute to tell a class that it should be materialized by a certain factory. We can also scan all types during the load of an assembly, so if an assembly is loaded, we can simply build new factories on-the-fly.

我牺牲这是编译时检查,但由于工厂模式通常使用的运行信息,这不一定是一个问题。

What I sacrifice for this is compile-time checks, but because the Factory pattern usually uses runtime information, that's not necessarily a problem.

结束语这一切,这是我厂的代码:

Wrapping it all up, here's the code of my Factory:

/// <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;
        }
    }
}

这篇关于命名约定GoF的工厂?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆