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

发布于 2024-08-06 14:37:15 字数 2804 浏览 1 评论 0原文

我制作了下面的示例,该示例使工厂能够将对象与功能打包在一起,但问题是功能与对象分离

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

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

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

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

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

与风相奔跑 2024-08-13 14:37:15

我个人会推荐一种更好的设计模式,例如访问者模式,但就其价值而言,您可以通过放弃类型安全来使代码正常工作。使用 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);
    }
}

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:

    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);
    }
}
暮年慕年 2024-08-13 14:37:15

这看起来像是访问者模式的经典案例。

算法(访问者)需要根据他们装饰(或访问)的对象进行定制,或者至少根据装饰对象实现的某些接口进行定制。

例如,您的 Employee 对象可能具有如下所示的方法:

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

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

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

最后,如果您想提供算法密钥并动态调用它们,您可以通过将它们存储在一个类似于现在的方式来实现IDictionary 成员。

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:

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):

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.

万水千山粽是情ミ 2024-08-13 14:37:15

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

I would check out the PostSharp project. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文