2015-05-20 3 views
2

мне интересно, если есть менее болезненный способ, чтобы написать что-то вроде следующего:Объект дизайн кэширования шаблон

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

Та часть, которая ошибок меня здесь есть все частные Ивар. Если у меня (скажем) 30 разных сотрудников, это становится трудоемким. Есть ли способ избежать наличия отдельного ivar для каждого сотрудника?

Мне вряд ли понадобится доступ к объектам сотрудника, кроме метода GetEmployeesPresentToday(). Другими словами, я не ожидаю, что какой-либо код будет спрашивать: «Кто твой генеральный директор?» или т.п.

Однако важно, чтобы при выполнении двух разных вызовов в GetEmployeesPresentToday() и Condition1 в указанном выше коде было истинно каждый раз, тогда в каждом списке должен появляться один и тот же главный объект.

+1

Тип отображения объектов в словаре вместо переменной для каждого типа сотрудников? – Ralf

+0

Может быть более одного сотрудника определенного типа; Я отредактировал вопрос, чтобы понять это. –

+0

Если вы можете дать ему отдельный variablename для меня другой тип. Я не имел в виду тип здесь в контексте класса и т. Д. – Ralf

ответ

0

Вот один из возможных ответов. Однако я не уверен, что это лучше или хуже кода в вопросе.

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

Я был бы соблазн использовать 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(); 
    } 
} 
Смежные вопросы