2017-04-07 53 views
-2

我有一個抽象類是這樣的:多態對象創建無IF條件

public abstract class Records 
    { 
     public string Type; 
     public string Source; 
     public int Value; 

     protected Records(string type, string source, int value) 
     { 
      Type = type; 
      Source = source; 
      Value = value; 
     } 
} 

我想創造出許多類繼承這個類,並從這樣的靜態類未來價值盡顯其類型字段:

public static class ContentTypesString 
    { 
     public static string DocumentNew { get { return "Document - New this Month"; }} 

     public static string HeadlinesNew { get { return "Headlines - New this Month"; }} 

     etc... 
    } 

我希望能夠不必測試「if foo == "document" then type = ContentTypesString.DocumentNew」或等效的開關情況下創建這些子類(我真的有很多的情況下)

有沒有適合我需求的設計模式?

編輯:正如幾個人指出的,我應該展示如何創建我的實例。

 private delegate SPListItemCollection Query(SPWeb web, DateTime startDate, DateTime endDate); 
    private readonly Query _queries; 

     #region Constructors 

     public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate) 
      { 
      if (web == null) throw new ArgumentNullException("web"); 

      _web = web; 
      _startTimeSelectedDate = startTimeSelectedDate; 
      _endTimeSelectedDate = endTimeSelectedDate; 
      RecordsList = new List<Records>(); 

      // Query Invocation List 
      _queries = NumberPagePerMonthQuery.PreparedQuery; 
      _queries += NumberDocumentsPerMonthQuery.PreparedQuery; 
      _queries += NumberHeadlinesPerMonthQuery.PreparedQuery; 
      _queries += NumberLeaderboxPerMonthQuery.PreparedQuery; 
      _queries += NumberNewsPerMonthQuery.PreparedQuery; 
      _queries += NumberPagesModifiedPerMonthQuery.PreparedQuery; 
      _queries += NumberPicturesPerMonthQuery.PreparedQuery; 
      _queries += NumberTeasingPerMonthQuery.PreparedQuery; 
     } 

     #endregion Constructors 

     #region Public Methods 

     // what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ? 
     /*** NO C#6 compiler in VS2012... ***/ 
     public void Queries() 
     { 
      foreach (var del in _queries.GetInvocationList()) 
      { 
       var queryresult = 
        (SPListItemCollection) del.DynamicInvoke(_web, _startTimeSelectedDate, _endTimeSelectedDate); 

       RecordsList.Add(new Records(del.Method.Name, _web.Title, queryresult.Count)); 
      } 
     } 

EDIT²: 我選擇

public List<IQuery> QueryList { get; } // no delegate anymore, and static classes became implementations of IQuery interface. 

     #region Constructors 

     public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate) 
      { 
      if (web == null) throw new ArgumentNullException("web"); 

      _web = web; 
      _startTimeSelectedDate = startTimeSelectedDate; 
      _endTimeSelectedDate = endTimeSelectedDate; 
      RecordsList = new List<Records>(); 

      QueryList = new List<IQuery> 
      { 
       new NumberDocumentsPerMonthQuery(), 
       new NumberHeadlinesPerMonthQuery(), 
       new NumberLeaderboxPerMonthQuery(), 
       new NumberNewsPerMonthQuery(), 
       new NumberPagePerMonthQuery(), 
       new NumberPagesModifiedPerMonthQuery(), 
       new NumberPicturesPerMonthQuery(), 
       new NumberTeasingPerMonthQuery() 
      }; 

     } 

     #endregion Constructors 

     #region Public Methods 

     // what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ? 
     /*** NO C#6 compiler in VS2012... ***/ 
      public void Queries() 
     { 
      foreach (var query in QueryList) 
      { 
       var queryresult = query.PreparedQuery(_web, _startTimeSelectedDate, _endTimeSelectedDate); 
       RecordsList.Add(query.CreateRecord(_web.Title, queryresult.Count)); 
      } 
     } 

Record類遵循@dbraillon IQUERY接口的實現建議的執行情況進行添加的方法解決之道:

public Records CreateRecord(string source, int value) 
     { 
      return new ModifiedPagesPerMonthRecord(source, value); //or another child of Record class. 
     } 

而且瞧。謝謝大家的幫助。

+0

爲什麼不直接在繼承類中進行呢? 'public class Documents:Records {public Documents(){Type = ContentTypesString.DocumentNew; }}' – DavidG

+0

爲什麼不直接放一些虛擬方法getDefaultContentTypeString? – gabba

+0

是的,但是我怎樣才能選擇在調用者中沒有IF的情況下製作哪些記錄? –

回答

0

您希望通過對象類型的字符串代碼和參數進行記錄收集。

許多方法之一 - 使用生成器。

首先,我們需要configurate建設者:

 var builder = new RecordBuilder() 
      .RegisterBuilder("document", (source, value) => new Document(source, value)) 
      .RegisterBuilder("headlines", (source, value) => new Headlines(source, value)); 

我們這裏確定如何構建紀錄代碼「文件」和「頭條新聞」。

要建立一個記錄電話:

 builder.Build("document", "source", 1); 

Builder代碼可以通過這樣的 (這裏我們來看看,如果我們知道如何建立與傳遞類型的記錄,並使它):

public class RecordBuilder 
{ 
    public Records Build(string code, string source, int value) 
    { 
     Func<string, int, Records> buildAction; 

     if (recordBuilders.TryGetValue(code, out buildAction)) 
     { 
      return buildAction(source, value); 
     } 

     return null; 
    } 

    public RecordBuilder RegisterBuilder(string code, Func<string, int, Records> buildAction) 
    { 
     recordBuilders.Add(code, buildAction); 
     return this; 
    } 

    private Dictionary<string, Func<string, int, Records>> recordBuilders = new Dictionary<string, Func<string, int, Records>>(); 
} 


public class Document : Records 
{ 
    public Document(string source, int value) : base(ContentTypesString.DocumentNew, source, value) 
    { 
    } 
} 

public class Headlines : Records 
{ 
    public Headlines(string source, int value) : base(ContentTypesString.HeadlinesNew, source, value) 
    { 
    } 
} 
+0

我不確定我是否理解你在這裏做什麼以及如何使用它,但它肯定看起來更像是我想在這裏重現的設計的(非常)模糊的記憶。 –

+0

@YthioCsi,我加了一些額外的解釋代碼 – gabba

+0

我想我找到了,我改變了我的程序了很多。保留prepareQuery的靜態實用程序方法成爲IQuery接口的實現,代理已被列表取代,並且代理調用列表被替換爲調用接口方法的列表上的foreach。接口IQuery的實現還包含一個返回所需的Record子實例的方法。 –

0

這就是你需要的嗎?

public abstract class Records 
{ 
    public string Type; 
    public string Source; 
    public int Value; 

    protected Records(string type, string source, int value) 
    { 
     Type = type; 
     Source = source; 
     Value = value; 
    } 
} 

public class DocumentRecords : Records 
{ 
    public DocumentRecords(string source, int value) 
     : base(ContentTypesString.DocumentNew, source, value) // use here 
    { 
    } 
} 

public class HeadlinesRecords : Records 
{ 
    public HeadlinesRecords(string source, int value) 
     : base(ContentTypesString.HeadlinesNew, source, value) // use here 
    { 
    } 
} 

public static class ContentTypesString 
{ 
    public static string DocumentNew { get { return "Document - New this Month"; } } 

    public static string HeadlinesNew { get { return "Headlines - New this Month"; } } 
} 
+0

這看起來不錯:)但我怎麼能選擇哪個記錄的孩子沒有IF在調用者? –

+0

所以起初,你只有一個類型,你想給這種類型的東西,將創建相應的記錄孩子回來嗎? – dbraillon

+0

我添加了一些關於如何創建記錄實例的代碼。我想擺脫我認爲很髒的Method.Name,並在此上下文中調用正確的Record子類構造函數。我有模糊的記憶,這是可能的,但我不記得如何。 –