简体   繁体   English

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

[英]What is the best way to "adorn objects with functionality"?

I made the example below which enables a factory to pack objects with functionality, but the problem is that the functionality is divorced from the object .我做了下面的例子,它使工厂能够打包具有功能的对象,但问题是功能与对象分离

My ultimate goal is attach functionality such as log , and save and display which operates on the specific properties that each different object has.我的最终目标是附加功能,例如logsavedisplay ,这些功能对每个不同对象具有的特定属性进行操作。

How would I keep the exterior adorning aspect of this example but enable functionality such as "save" which saves the object's data to a database or "log" which logs its activity?我将如何保留此示例的外部装饰方面,但启用诸如“保存”将对象的数据保存到数据库或记录其活动的“日志”等功能?

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

}

I would personally recommend a better design pattern, like the visitor pattern, but for what its worth you can make your code work by throwing away type safety.我个人会推荐一种更好的设计模式,比如访问者模式,但不管怎样,你可以通过抛弃类型安全来让你的代码工作。 Use Delegate rather than its derived classes Func and Action :使用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);
    }
}

This looks like a classic case for the visitor pattern .这看起来像是访问者模式的经典案例。

The algorithms (visitors) will need to be tailored to the objects they adorn (or visit), or at least tailored to some interface that your adorned objects implement.算法(访问者)需要根据他们装饰(或访问)的对象进行定制,或者至少根据您的装饰对象实现的某些接口进行定制。

For example, your Employee object might have a method like the following:例如,您的Employee对象可能具有如下所示的方法:

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

IEmployeeAlgorithm objects would have an interface similar to this (these could just as easily be Action<Employee> delegates, or use other signatures as needed): IEmployeeAlgorithm对象将具有与此类似的接口(这些可以很容易地成为Action<Employee>委托,或根据需要使用其他签名):

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

Finally, if you want to give the algorithms keys and invoke them dynamically, you could do that in a fashion similar to what you've got now by storing them in an IDictionary<string, IEmployeeAlgorithm> member.最后,如果您想提供算法键并动态调用它们,您可以通过将它们存储在IDictionary<string, IEmployeeAlgorithm>成员中,以类似于您现在所获得的方式执行此操作。

I would check out the PostSharp project.我会查看PostSharp项目。 They allow this kind of separation of concerns and enable some easy ways to accomplish this.它们允许这种关注点分离并启用一些简单的方法来实现这一点。 They allow you to externally define code which is added to classes/properties at run time.它们允许您在外部定义在运行时添加到类/属性的代码。 I'm not sure about your specific requirements (or this particular example) but you should check it out.我不确定您的具体要求(或此特定示例),但您应该检查一下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当用户在文本框中键入时,提供即时搜索功能的最佳方式是什么 - what is the best way of providing instant search functionality as a user types in a textbox 使用 linq 迭代对象的最佳方法是什么 - What is the best way to iterate objects using linq 划分两个TimeSpan对象的最佳方法是什么? - What is the best way to divide two TimeSpan objects? 序列化循环引用对象的最佳方法是什么? - What is the best way to serialize circular referenced objects? 备份大对象的最佳方法是什么? - What is the best way to backup large objects? 绘制对象并对其进行处理的最佳方法是什么? - What is the best way to draw objects and deal with them? 在 C# 中的字典中存储类似对象的最佳方法是什么? - What is the best way to store similar objects in a dictionary in C#? 确定收集对象的初始容量的最佳方法是什么? - What is the best way to determine the initial capacity for collection objects? 在C#中为现有代码添加自定义功能的最佳方法是什么? - What's the best way to add custom functionality to existing code in C#? 在WinForms中实现干净的UI功能同时保持良好的解耦架构的最佳方法是什么? - What's the best way to implement clean UI functionality in WinForms while maintaining a decent decoupled architecture?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM