2009-10-08 62 views
2

我提出下面其使得工厂与功能包对象的例子,但问题是官能度为从物体离婚。“用功能装饰物体”的最佳方法是什么?

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

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

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

我缺少的东西或将扩展方法解决这个多一点优雅? – Joey 2009-10-08 14:43:03

+0

或可能的属性。 – 2009-10-08 14:50:45

+0

在附注中,我认为单例的JIT实例化不是线程安全的。正确的方法是将其实例化为现场声明的一部分;这是保证工作。 – 2009-10-08 15:57:34

回答

2

我个人会推荐一个更好的设计模式,比如访问者模式,但是它的价值可以通过丢弃类型安全来让你的代码工作。使用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); 
    } 
} 
+0

为什么来访者而不是装饰者? – 2009-10-08 15:15:46

+1

当然,Decorator是合理的,但装饰者应该实现他们装饰的类的接口,所以它可以做更多的工作。 (另外,根据Edward的例子,看起来装饰器会提供与他所寻找的抽象不同的抽象:封装现有接口的扩展版本,而不是封装在这些接口上运行的算法。) – 2009-10-08 15:30:02

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

最后,如果你想给算法的密钥和动态调用它们,你能做到这在类似的方式你已经通过将它们存储在一现在得到了什么成员。

0

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

相关问题