我做了下面的示例,它使工厂能够打包具有功能的对象,但问题是功能与对象脱离。
我的最终目标是附加功能,例如日志,以及保存和显示,这些功能针对每个不同对象具有的特定属性进行操作。
如何保留此示例的外部装饰方面,但是启用将“保存”功能保存到数据库的“保存”或记录其活动的“日志”等功能?
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; }
}
}
答案 0 :(得分:2)
我个人会推荐一个更好的设计模式,比如访问者模式,但是你可以通过抛弃类型安全来使你的代码工作。使用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);
}
}
答案 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项目。它们允许这种关注点的分离,并使一些简单的方法能够实现这一点。它们允许您从外部定义在运行时添加到类/属性的代码。我不确定您的具体要求(或此特定示例),但您应该查看它。