簡體   English   中英

對象緩存設計模式

[英]Object caching design pattern

我想知道是否有一種減輕痛苦的方式來編寫如下內容:

public class Company {
  // CEO, Programmer, and Janitor all inherit from an Employee class.
  private CEO _CacheCEO {get;} = CEOFactory.NewCEO();
  private Programmer _CacheJavaProgrammer {get;} = ProgrammerFactory.NewJavaProgrammer();
  private Programmer _CacheIOSProgrammer {get;} = ProgrammerFactory.NewIOSProgrammer();
  private Janitor _CacheJanitor {get;} = JanitorFactory.NewJanitor();
  // etc.
  public IEnumerable<Employee> GetEmployeesPresentToday() {
    List<Employee> r = new List<Employee>();
    if (ExternalCondition1) {   // value of the condition may differ on successive calls to this method
      r.Add(this._CacheCEO);
    };
    if (ExternalCondition2) {  // all conditions are external to the Company class, and it does not get notified of changes.
      r.Add(this._CacheJavaProgrammer);
    }
    if (ExternalCondition3) {
      r.Add(this._CacheIOSProgrammer);
    }
    if (ExternalCondition4) {
      r.Add(this._CacheJanitor);
    }
    // etc.
    return r;
  }

讓我煩惱的是所有私人IVar。 如果我有(說)30個不同的員工,那會很麻煩。 有沒有一種方法可以避免為每個員工使用單獨的ivar?

除了通過GetEmployeesPresentToday()方法之外,我不太可能需要對雇員對象的任何訪問。 換句話說,我不希望任何代碼詢問“誰是您的CEO?” 或類似的東西。

但是,重要的是,如果對GetEmployeesPresentToday()進行了兩次不同的調用,並且上述代碼中的Condition1每次都為true,則同一CEO對象應出現在每個列表中。

這是一個可能的答案。 但是,我不確定它是比問題中的代碼好還是壞。

public class Company {
  private Dictionary<string, Employee> _CacheEmployees { get;} = new Dictionary<string, Employee>();

  public Employee GetEmployee(string key, Func<Employee> factory) {
    // Existence of this method is not really annoying as it only has to be written once.
    private Dictionary<string, Employee> cache = this._CacheEmployees;
    Employee r = null;
    if (cache.ContainsKey(key)) {
      r = cache[key];
    }
    if (r == null) {
      r = factory();
      cache[key] = r;
    }
    return r;
  }

  public IEnumerable<Employee> GetEmployeesPresentToday() {
    // still somewhat messy, but perhaps better than the question code.
    List<Employee> r = new List<Employee>();
    if (ExternalCondition1) {   // value of the condition may differ on successive calls to this method
      r.Add(this.GetEmployee("CEO", CEOFactory.NewCEO));
    };
    if (ExternalCondition2) {   // all conditions are external to the Company class, and it does not get notified of changes.
      r.Add(this.GetEmployee("Java Programmer", ProgrammerFactory.NewJavaProgrammer));
    }
    if (ExternalCondition3) {
      r.Add(this.GetEmployee("IOS Programmer", ProgrammerFactory.NewIOSProgrammer));
    }
    if (ExternalCondition4) {
      r.Add(this.GetEmployee("Janitor", JanitorFactory.NewJanitor));
    }
    // etc.
    return r;
  }
}

我很想將Lazy<T>Dictionary<T,V>一起使用以實現完全惰性的實現,例如:

public sealed class Company
{
    private readonly Dictionary<string, Lazy<Employee>> _cache = new Dictionary<string, Lazy<Employee>>();

    public Company()
    {
        _cache["CEO"]            = new Lazy<Employee>(CeoFactory.NewCeo);
        _cache["Janitor"]        = new Lazy<Employee>(JanitorFactory.NewJanitor);
        _cache["IosProgrammer"]  = new Lazy<Employee>(ProgrammerFactory.NewIosProgrammer);
        _cache["JavaProgrammer"] = new Lazy<Employee>(ProgrammerFactory.NewJavaProgrammer);
    }

    public IEnumerable<Employee> GetEmployeesPresentToday(bool cond1, bool cond2, bool cond3, bool cond4)
    {
        if (cond1)
            yield return _cache["CEO"].Value;

        if (cond2)
            yield return _cache["JavaProgrammer"].Value;

        if (cond3)
            yield return _cache["IosProgrammer"].Value;

        if (cond4)
            yield return _cache["Janitor"].Value;
    }

要考慮的另一件事是Dictionary<string,bool>用於指定要返回的雇員,而不是單獨的布爾值。 然后, GetEmployeesPresentToday()方法可能如下所示:

public IEnumerable<Employee> GetEmployeesPresentToday(Dictionary<string, bool> want)
{
    if (want["CEO"])
        yield return _cache["CEO"].Value;

    if (want["JavaProgrammer"])
        yield return _cache["JavaProgrammer"].Value;

    if (want["IosProgrammer"])
        yield return _cache["IosProgrammer"].Value;

    if (want["Janitor"])
        yield return _cache["Janitor"].Value;
}

或者,您可以通過傳入Predicate<string>使其更通用,從而使條件檢查的實現不會暴露給GetEmployeesPresentToday()

public IEnumerable<Employee> GetEmployeesPresentToday(Predicate<string> want)
{
    if (want("CEO"))
        yield return _cache["CEO"].Value;

    if (want("JavaProgrammer"))
        yield return _cache["JavaProgrammer"].Value;

    if (want("IosProgrammer"))
        yield return _cache["IosProgrammer"].Value;

    if (want("Janitor"))
        yield return _cache["Janitor"].Value;
}

請注意,為避免輸入錯誤的可能性,您可能希望對字符串使用常量,而不是在多個位置鍵入它們。 然后,如果您將常數拼寫錯誤,則會出現編譯錯誤。

另請注意,我稍稍更改了代碼以確保已編譯。 我使用了以下測試類:

public abstract class Employee
{
}

public sealed class Ceo: Employee
{
}

public abstract class Programmer: Employee
{
}

public sealed class JavaProgrammer: Programmer
{
}

public sealed class IosProgrammer: Programmer
{
}

public sealed class Janitor: Employee
{
}

public static class ProgrammerFactory
{
    public static Programmer NewJavaProgrammer()
    {
        return new JavaProgrammer();
    }

    public static Programmer NewIosProgrammer()
    {
        return new IosProgrammer();
    }
}

public static class CeoFactory
{
    public static Ceo NewCeo()
    {
        return new Ceo();
    }
}

public static class JanitorFactory
{
    public static Janitor NewJanitor()
    {
        return new Janitor();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM