代码之家  ›  专栏  ›  技术社区  ›  Edward Tanguay

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

  •  2
  • Edward Tanguay  · 技术社区  · 15 年前

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

    我的最终目标是附加功能,例如 日志 节约 显示 它对每个不同对象具有的特定属性进行操作。

    我如何保持这个例子的外部装饰方面,但启用诸如“保存”这样的功能,将对象的数据保存到数据库中,或者“日志”记录其活动?

    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 回复  |  直到 15 年前
        1
  •  2
  •   Juliet    15 年前

    我个人会推荐一个更好的设计模式,比如访问者模式,但是为了它的价值,您可以通过放弃类型安全性来让代码工作。使用 Delegate 而不是它的派生类 Func Action :

        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);
        }
    }
    
        2
  •  1
  •   Jeff Sternal    15 年前

    这看起来像是 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> 成员。

        3
  •  0
  •   luke    15 年前

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

    推荐文章