[英]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.我的最终目标是附加功能,例如log 、 save和display ,这些功能对每个不同对象具有的特定属性进行操作。
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
而不是它的派生类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);
}
}
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.