[英]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.