“装饰具有功能的对象”的最佳方法是什么?

时间:2009-10-08 14:40:20

标签: c# dependency-injection aop adorner

我做了下面的示例,它使工厂能够打包具有功能的对象,但问题是功能与对象脱离

我的最终目标是附加功能,例如日志,以及保存显示,这些功能针对每个不同对象具有的特定属性进行操作。

如何保留此示例的外部装饰方面,但是启用将“保存”功能保存到数据库的“保存”或记录其活动的“日志”等功能?

using System;
using System.Collections.Generic;

namespace FuncAdorn3923
{
    class Program
    {
        static void Main(string[] args)
        {

            Customer customer = new Customer();
            ObjectFactory.Instance.AdornFunctionality(customer, "add");
            Console.WriteLine(customer.CallAlgorithm("add", 64, 36));

            Employee employee = new Employee();
            ObjectFactory.Instance.AdornFunctionality(employee, "add");
            ObjectFactory.Instance.AdornFunctionality(employee, "subtract");
            Console.WriteLine(employee.CallAlgorithm("add", 5, 15));
            Console.WriteLine(employee.CallAlgorithm("subtract", 66, 16));

            Console.ReadLine();
        }
    }

    public class ObjectFactory
    {
        private static ObjectFactory singleton;

        public void AdornFunctionality(AdornedObject ao, string idCode)
        {
            Func<int, int, int> add = (i, j) => i + j;
            Func<int, int, int> subtract = (i, j) => i - j;

            switch (idCode)
            {
                case "add":
                    ao.LoadAlgorithm(idCode, add);
                    break;
                case "subtract":
                    ao.LoadAlgorithm(idCode, subtract);
                    break;
            }
        }

        public static ObjectFactory Instance
        {
            get
            {
                if (singleton == null)
                    singleton = new ObjectFactory();
                return singleton;
            }
        }

    }

    public abstract class AdornedObject
    {
        private Dictionary<string, Func<int, int, int>> algorithms = 
            new Dictionary<string, Func<int, int, int>>();

        public void LoadAlgorithm(string idCode, Func<int,int,int> func)
        {
            algorithms.Add(idCode, func);
        }

        public int CallAlgorithm(string idCode, int i1, int i2)
        {
            Func<int,int,int> func = algorithms[idCode];
            return func.Invoke(i1, i2);
        }
    }

    public class Customer : AdornedObject
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int NumberOfProductsBought { get; set; }
    }

    public class Employee : AdornedObject
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }

}

3 个答案:

答案 0 :(得分:2)

我个人会推荐一个更好的设计模式,比如访问者模式,但是你可以通过抛弃类型安全来使你的代码工作。使用Delegate而不是其派生类FuncAction

    static void Main(string[] args)
    {

        Customer customer = new Customer();
        ObjectFactory.Instance.AdornFunctionality(customer, "add");
        Console.WriteLine(customer.CallAlgorithm("add", 64, 36));

        Employee employee = new Employee();
        ObjectFactory.Instance.AdornFunctionality(employee, "add");
        ObjectFactory.Instance.AdornFunctionality(employee, "subtract");
        ObjectFactory.Instance.AdornFunctionality(employee, "save");
        Console.WriteLine(employee.CallAlgorithm("add", 5, 15));
        Console.WriteLine(employee.CallAlgorithm("subtract", 66, 16));
        Console.WriteLine(employee.CallAlgorithm("save"));

        Console.ReadLine();
    }
}

public class ObjectFactory
{
    private static ObjectFactory singleton;

    public void AdornFunctionality(AdornedObject ao, string idCode)
    {
        Func<int, int, int> add = (i, j) => i + j;
        Func<int, int, int> subtract = (i, j) => i - j;
        Action save = () => Console.WriteLine("{0} has been saved", ao.ToString());

        switch (idCode)
        {
            case "add":
                ao.LoadAlgorithm(idCode, add);
                break;
            case "subtract":
                ao.LoadAlgorithm(idCode, subtract);
                break;
            case "save":
                ao.LoadAlgorithm(idCode, save);
                break;
        }
    }

    public static ObjectFactory Instance
    {
        get
        {
            if (singleton == null)
                singleton = new ObjectFactory();
            return singleton;
        }
    }

}

public abstract class AdornedObject
{
    private Dictionary<string, Delegate> algorithms = new Dictionary<string, Delegate>();

    public void LoadAlgorithm(string idCode, Delegate func)
    {
        algorithms.Add(idCode, func);
    }

    public object CallAlgorithm(string idCode, params object[] args)
    {
        Delegate func = algorithms[idCode];
        return func.DynamicInvoke(args);
    }
}

答案 1 :(得分:1)

这看起来像是visitor pattern的经典案例。

算法(访问者)需要针对他们装饰(或访问)的对象进行定制,或至少针对您的装饰对象实现的某个界面进行定制。

例如,您的Employee对象可能有以下方法:

public class Employee: IEmployee {
    public void Accept(IEmployeeAlgorithm algorithm) {
        algorithm.Visit(this);
    }
}

IEmployeeAlgorithm个对象将具有与此类似的接口(这些可以很容易地成为Action<Employee>个委托,或者根据需要使用其他签名):

public interface IEmployeeAlgorithm {
    void Visit(IEmployee employee);
}

最后,如果你想给算法键并动态调用它们,你可以通过将它们存储在IDictionary<string, IEmployeeAlgorithm>成员中,以类似于你现在的方式来做到这一点。

答案 2 :(得分:0)

我会查看PostSharp项目。它们允许这种关注点的分离,并使一些简单的方法能够实现这一点。它们允许您从外部定义在运行时添加到类/属性的代码。我不确定您的具体要求(或此特定示例),但您应该查看它。