Csharp/C#教程:GoF Factory的命名约定?分享


GoF Factory的命名约定?

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

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

例如:

public abstract class ChocolateFactory { };

public class MyChocolateFactory { } : ChocolateFactory

这里的标准惯例是什么?

我正在考虑ChocolateFactoryBase或ConcreteChocolateFactory,但也许还有别的东西(很像Enum往往以Enum为后缀,例如PetTypeEnum这样你就可以做PetTypeEnum PetType;

希望这不是主观的。

问题和答案

好的,这个问题始于抽象工厂的命名问题。 根据经验,总是使用你正在做的“正式”名称(例如工厂,装饰师等)和具体实现的描述(例如士力架,火星,MotifWidget等等)。

所以基本上,你创建一个MSSQLConnection ,它是你描述的具体事物,而Factory意味着它遵循工厂模式的特征。

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

抽象的工厂和工厂

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

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

工厂模式

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

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

你通常用这个来抽象东西。 例如,生成XML节点的HTML解析器中的内容会根据HTML标记创建特定类型的节点。

工厂通常根据运行时信息做出决策。 因此可以概括Factory模式来实现以下内容:

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

使用RTTI创建通用工厂模式非常容易,RTTI为每个名称存储一个Type 。 查找名称,使用reflection创建对象。 完成。

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

概括抽象工厂

抽象工厂基本上是工厂的集合,它们以与Factory模式相同的方式创建对象。 唯一共享的是接口(例如Create或者您可以使用inheritance来创建抽象)。

实施是非常微不足道的,所以我就把它留在那里。

解耦工厂和类型

让我们回到GoF示例。 他们谈论MotifFactoryPMFactory 。 在未来,我们将遇到另一个UI thingie,我们需要一个ASPNETFactorySilverlightFactory 。 然而,未来是未知的,如果我们不需要,我们宁愿不发送旧的DLL – 毕竟,这不灵活。

如果我们想为工厂添加新方法,则会产生第二个问题。 因此,这样做将涉及改变所有工厂。 你可能已经猜到了,我不想在多个地方改变它。

幸运的是,我们可以解决这两个问题。 界面是相同的(甚至可以推广),因此我们可以在运行时简单地向工厂添加新function。

我们可以使用属性来告诉类它应该某个工厂实现而不是告诉工厂要创建的对象。 我们还可以在assembly过程中扫描所有类型,因此如果装载了assembly,我们可以简单地即时构建新工厂。

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

把它全部包装起来,这是我工厂的代码:

 ///  /// This attribute is used to tag classes, enabling them to be constructed by a Factory class. See the  /// class for details. ///  ///  ///  /// It is okay to mark classes with multiple FactoryClass attributes, even when using different keys or different factories. ///  ///  ///  [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] public class FactoryClassAttribute : Attribute { ///  /// This marks a class as eligible for construction by the specified factory type. ///  ///  /// [FactoryClass("ScrollBar", typeof(MotifFactory))] /// public class MotifScrollBar : IControl { } ///  /// The key used to construct the object /// The type of the factory class 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; } ///  /// The key used to construct the object when calling the  method. ///  public object Key { get; private set; } ///  /// The type of the factory class ///  public Type FactoryType { get; private set; } } ///  /// Provides an interface for creating related or dependent objects. ///  ///  ///  /// This class is an implementation of the Factory pattern. Your factory class should inherit this Factory class and /// you should use the [] 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  type and are stored by key. During runtime, you can /// use the Factory class implementation to build objects of the correct type. ///  ///  /// 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). ///  ///  /// Implementation of the Strategy pattern can be done by using the Factory pattern and making the  /// 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. ///  ///  /// The type of the key to use for looking up the correct object type /// The base interface that all classes created by the Factory share ///  /// The factory class automatically hooks to all loaded assemblies by the current AppDomain. All classes tagged with the FactoryClass /// are automatically registered. ///  ///  ///  /// // 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<string, IControl> /// { /// 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 ///  ///  public abstract class Factory : IFactory where Intf : class { ///  /// Creates a factory by mapping the keys of the create method to the keys in the FactoryClass attributes. ///  protected Factory() : this((a) => (a)) { } ///  /// 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. ///  /// A function that maps keys passed to  to keys used with [] protected Factory(Func typeConversion) { this.typeConversion = typeConversion; } private Func typeConversion; private static object lockObject = new object(); private static Dictionary> dict = null; ///  /// Creates an instance a class registered with the  attribute by looking up the 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. /// An instance of the factory class public virtual Intf Create(Key key) { Dictionary> dict = Init(); Dictionary factoryDict; if (dict.TryGetValue(this.GetType(), out factoryDict)) { Type t; return (factoryDict.TryGetValue(typeConversion(key), out t)) ? (Intf)Activator.CreateInstance(t) : null; } return null; } ///  /// Creates an instance a class registered with the  attribute by looking up the 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. /// Additional parameters that have to be passed to the constructor /// An instance of the factory class public virtual Intf Create(Key key, params object[] constructorParameters) { Dictionary> dict = Init(); Dictionary 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; } ///  /// Enumerates all registered attribute keys. No transformation is done here. ///  /// All keys currently known to this factory public virtual IEnumerable EnumerateKeys() { Dictionary> dict = Init(); Dictionary 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> Init() { Dictionary> 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> classDict = new Dictionary>(); foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies()) { AddAssemblyTypes(classDict, ass); } dict = classDict; } private void AddAssemblyTypes(Dictionary> 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 keyDict; if (!classDict.TryGetValue(f.FactoryType, out keyDict)) { keyDict = new Dictionary(); 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> classDict = new Dictionary>(dict); dict = null; Thread.MemoryBarrier(); AddAssemblyTypes(classDict, args.LoadedAssembly); dict = classDict; } } } 

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

  1. “抽象”部分可以是一个界面 – >“公约”将是“ 我的名字大全”
  2. 你的基类应该描述关于它的实现的“常见”事情,信息位于上下文中:如果在你的上下文中,ChocolateFactory可能是一个“抽象”概念,那么实现(应该描述具体的东西(MyChocolateFactory不是一个好名字大全)) )应该显示他们(是)的关系,但也应该显示具体的用例。
  3. 关于您的评论:如果不需要任何其他工厂实施只是为了将来可能的用例,请不要使用抽象工厂;)

你可以使用这样的东西:

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

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

上述就是C#学习教程:GoF Factory的命名约定?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1009649.html

(0)
上一篇 2021年12月29日
下一篇 2021年12月29日

精彩推荐