2009-10-08 91 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項目。他們允許這種關注的分離,並使一些簡單的方法來實現這一點。它們允許您在運行時從外部定義添加到類/屬性的代碼。我不確定你的具體要求(或這個特定的例子),但你應該檢查出來。

相關問題