65.9K
CodeProject 正在变化。 阅读更多。
Home

委托工厂

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.92/5 (8投票s)

2005年1月11日

CPOL

3分钟阅读

viewsIcon

61011

downloadIcon

183

使用委托的动态工厂

引言

本文的目标是展示另一种使用委托的工厂实现。我曾在 CodeProject 上搜索过类似的实现,虽然有一些很接近,但它们并不完全相同。所以我决定发布我当前项目中使用的这个工厂。

本文的目标不是解释工厂的整个概念,也不是解释为什么你会使用这种特定的设计模式。

目录

目标

编写这个工厂的目标如下

  1. 动态工厂 - 将来有可能在不打开工厂代码的情况下,将同一工厂用于新型对象。
  2. 创建责任 - 工厂不应该知道如何创建对象。
  3. 易于使用。

使用委托

使用委托将帮助我们实现目标 12,它可能会让我们与目标 3 发生冲突,但我们会看到。

委托的声明如下所示

/// <SUMMARY>
/// A handler function for the factory to create objects;
/// </SUMMARY>

public delegate AObject ObjectCreator(params object [] list);

这个委托将帮助我们隐藏对象从工厂创建的方式,并帮助我们在工厂上注册这种类型的委托。

实现对象层次结构

工厂将在我们的树中创建我们的第一个可用对象,这样我们就不必直接向下转型(只有在真正需要的情况下)。

基类是 abstract 并且定义了一个变量成员和一个 abstract 函数

/// <SUMMARY>
/// Summary description for AObject.
/// </SUMMARY>

public abstract class AObject
{
    #region Override

    /// <SUMMARY>
    /// Force all descendents to implement.
    /// </SUMMARY>

    public abstract void Print();

    #endregion

    #region protected

    /// <SUMMARY>Some variable to play with.</SUMMARY>

    protected Int32 m_nType;

    #endregion
}

派生类如下所示

/// <SUMMARY>
/// Summary description for Class1.
/// </SUMMARY>

public class Class1 : AObject
{
    #region Constants

    /// <SUMMARY>
    /// The class type identifier.
    /// </SUMMARY>

    public const Int32 ClassType = 1;

    #endregion
        
    #region C'tor

    /// <SUMMARY>
    /// Default C'tor.
    /// </SUMMARY>

    internal Class1()
    {
        this.m_nType = ClassType;
    }

    #endregion

    #region Overrides

    /// <SUMMARY>
    /// Implementation of Print.
    /// </SUMMARY>

    public override void Print()
    {
        String msg = String.Format("Class: {0, 20} Value: {1, 10}",
                                          ToString(), m_nType*67);
        Console.WriteLine(msg);
    }

    #endregion

    #region Static

    /// <SUMMARY>
    /// A handler function for the factory to create objects;
    /// </SUMMARY>

    /// The parameter list.
    /// <RETURNS>A Class1 object.</RETURNS>

    public static AObject ObjectCreator(params object[] list)
    {
        return new Class1();
    }

    #endregion
}

正如你所看到的,我们为派生类实现了一个 Print 函数,它做了一些事情(希望与其他的派生类不同),并且我们添加了一个 static 函数,用于创建 Class1 的新对象。

static 函数 ObjectCreator 负责在类中创建对象。

工厂

factory 类借助委托将类的 static 函数映射到我们想要创建的类型。

映射是通过一个哈希表完成的,其中对象的类型是键,封装 static 函数的委托是

工厂

/// <SUMMARY>
/// Summary description for ObjectFactory.
/// </SUMMARY>

public class ObjectFactory
{
    #region Static

    /// <SUMMARY>
    /// Register handler functions to create new types of objects.
    /// </SUMMARY>

    /// The type of the object.
    /// The handler function.
    /// <RETURNS>true if successful.</RETURNS>

    public static bool RegisterHandler(Int32 type, ObjectCreator creator)
    {
        bool res = false;
        try
        {
            if (m_handlers[type] != null)
                return false;
            // insert the handler to the table according to the type.
            m_handlers[type] = creator;
            res = true;
        }
        catch(Exception ex)
        {
            Console.WriteLine("Can't register handler - "+ex.Message);
        }
        return res;
    }

    /// <SUMMARY>
    /// Unregister handler functions according to type.
    /// </SUMMARY>

    /// The type of the object.
    /// <RETURNS>true if successful.</RETURNS>

    public static bool UnregisterHandler(Int32 type)
    {
        bool res = true;
        try
        {
            if (m_handlers[type] == null)
                return res;
            // remove the handler to the table according to the type.
            m_handlers[type] = null;
            GC.Collect();
        }
        catch(Exception ex)
        {
            Console.WriteLine("Can't unregister handler - "+ex.Message);
            res = false;
        }
        return res;
    }

    /// <SUMMARY>
    /// This is the static method that creates all types of objects.
    /// </SUMMARY>

    /// <REMARKS>Factory method.</REMARKS>

    /// The key of objects to create.
    /// The parameter list for the object.
    /// <RETURNS>An object.</RETURNS>

    public static AObject CreateObject(Int32 type, params object [] list)
    {
        AObject aobject = null;
        try
        {
            // get the handler that creates the objects
            ObjectCreator creator = (ObjectCreator)m_handlers[type];
            // create the object with the handler.
            if (creator != null)
                aobject = creator(list);
        }
        catch(Exception ex)
        {
            Console.WriteLine("Can't get object from handler - "+ex.Message);
        }
        return aobject;
    }

    #endregion

    #region Protected

    /// <SUMMARY> A table holding the handlers for creating objects. </SUMMARY>
    protected static Hashtable m_handlers = new Hashtable();

    #endregion
}

请注意,factoryregisterunregister 函数,稍后,我们将看到如何使用它们。

  • RegisterHandler - register 函数接受一个委托,并将其插入哈希表,其中类标识符作为键。
  • UnregisterHandler - unregister 函数接受 type 并删除作为 的任何委托。
  • CreateObject - 根据其 type (键)创建对象的函数。这个函数从哈希表中提取一个委托,从 type 的位置 并调用委托(调用我们之前注册的对象的 static 函数)。

使用工厂

在收到许多受人尊敬的同事的评论后,我稍微修改了以下代码,这样更明显的是,工厂并不知道它得到什么类型,而是检查它是否知道如何使用提供的键(类型)创建对象。

static void Main(string[] args)
{
    try
    {
        // registering the types that the factory will create
        ObjectFactory.RegisterHandler(Class1.ClassType, 
                new ObjectCreator(Class1.ObjectCreator));
        ObjectFactory.RegisterHandler(Class2.ClassType, 
                new ObjectCreator(Class2.ObjectCreator));
        ObjectFactory.RegisterHandler(Class3.ClassType, 
                new ObjectCreator(Class3.ObjectCreator));

        AObject aobject = null;
        // creating the objects
        for (int i = 0; i<100; i++)
        {
                aobject = ObjectFactory.CreateObject(i%3+1, null);
                aobject.Print();
        }
        // unregistering a type
        if (!ObjectFactory.UnregisterHandler(Class1.ClassType))
            Console.WriteLine("Really ?!");

        // trying to create an unregistered type
        aobject = ObjectFactory.CreateObject(Class1.ClassType, null);
        if (aobject != null)
            aobject.Print();
        else
            Console.WriteLine("aobject is null");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.ReadLine();
}

注意注册过程

我们传递一个要注册的 type,并且我们创建一个新的委托,将注册类型的 static 函数传递给它。我们必须确保在我们可以使用工厂创建对象之前注册 type,所以注册过程应该尽可能早地在程序中进行。

还要注意的一件事是,Class3(如果你已经下载了代码,你可能已经注意到)属于与 Main 相同的 namespace(和程序集),而不是属于其他类所属的 namespace(和程序集)。这意味着我们已经实现了目标 1 和目标 2。

我留给你来决定是否实现了目标 3。

© . All rights reserved.