2017-02-27 87 views
0

我有一些自定義集合類。每個服務提供各種自定義類型的集合 - 一個自定義類型到一個自定義集合。自定義集合繼承List<T> [其中T在這種情況下是特定的自定義類型,而不是泛型]並提供一些附加功能。幾乎具有共同代碼的類

我以前沒有使用自定義集合並在其他地方使用自定義方法,但是我發現在擴展代碼時需要使用自己的方法進行集合。

這一切正常,一切都很開心。但它激怒了我,因爲我知道我做得不好。問題是,每個類使用幾乎相同的代碼,只改變類型和參數,所以我覺得它可以實現爲抽象類,或泛型,或List的擴展,或...但我沒有真正理解這些差異或者如何去解決我需要的東西。

這裏是我的兩個數的集合,讓你的想法:

// JourneyPatterns 
public class JourneyPatterns : List<JourneyPattern> 
{ 
    private Dictionary<string, JourneyPattern> jpHashes;  // This is a hash table for quick lookup of a JP based on its values 

    /* Add a journey pattern to the JourneyPatterns collection. Three methods for adding: 
     1. "Insert Before" (=at) a particular point in the list. This is the method used by all three methods. 
     2. "Insert After" a particular point in the list. This is "before" shifted by 1 e.g. "after 6" is "before 7" 
     3. "Append" to the end of the list. This is "before" with a value equal to the list count, and is the same as inherited "Add", but with checks 
    */ 
    public JourneyPattern InsertBefore(JourneyPattern JP, int before) 
    { 
     // check for a pre-existing JP with the same parameters (ignore ID). Do this by constructing a "key" based on the values to check against 
     // and looking it up in the private hash dictionary 
     JourneyPattern existingJP; 
     if (jpHashes.TryGetValue(JP.hash, out existingJP)) { return existingJP; } 
     else 
     { 
      // construct a new ID for this JP 
      if (string.IsNullOrWhiteSpace(JP.id)) JP.id = "JP_" + (Count + 1).ToString(); 
      // next check that the ID specified isn't already being used by a different JPS 
      if (Exists(a => a.id == JP.id)) JP.id = "JP_" + (Count + 1).ToString(); 
      // now do the add/insert 
      if (before < 0) { Insert(0, JP); } else if (before >= Count) { Add(JP); } else { Insert(before, JP); } 
      // finally add to the hash table for fast compare/lookup 
      jpHashes.Add(JP.hash, JP); 
      return JP; 
     } 
    } 
    public JourneyPattern InsertAfter(JourneyPattern JP, int after) { return InsertBefore(JP, after + 1); } 
    public JourneyPattern Append(JourneyPattern JP) { return InsertBefore(JP, Count); } 
} 

// JourneyPatternSections 
public class JourneyPatternSections : List<JourneyPatternSection> 
{ 
    private Dictionary<string, JourneyPatternSection> jpsHashes;  // This is a hash table for quick lookup of a JPS based on its values 

    /* Add a journey pattern section to the journeyPatternSections collection. Three methods for adding: 
     1. "Insert Before" (=at) a particular point in the list. This is the method used by all three methods. 
     2. "Insert After" a particular point in the list. This is "before" shifted by 1 e.g. "after 6" is "before 7" 
     3. "Append" to the end of the list. This is "before" with a value equal to the list count, and is the same as inherited "Add", but with checks 
    */ 
    public JourneyPatternSection InsertBefore(JourneyPatternSection JPS, int before) 
    { 
     // check for a pre-existing JPS with the same parameters (ignore ID). Do this by constructing a "key" based on the values to check against 
     // and looking it up in the private hash dictionary 
     JourneyPatternSection existingJPS; 
     if (jpsHashes.TryGetValue(JPS.hash, out existingJPS)) { return existingJPS; } 
     else 
     { 
      // construct a new ID for this JPS 
      if (string.IsNullOrWhiteSpace(JPS.id)) JPS.id = "JPS_" + (Count + 1).ToString(); 
      // next check that the ID specified isn't already being used by a different JPS 
      if (Exists(a => a.id == JPS.id)) JPS.id = "JPS_" + (Count + 1).ToString(); 
      // now do the add/insert 
      if (before < 0) { Insert(0, JPS); } else if (before >= Count) { Add(JPS); } else { Insert(before, JPS); } 
      // finally add to the hash table for fast compare/lookup 
      jpsHashes.Add(JPS.hash, JPS); 
      return JPS; 
     } 
    } 
    public JourneyPatternSection InsertAfter(JourneyPatternSection JPS, int after) { return InsertBefore(JPS, after + 1); } 
    public JourneyPatternSection Append(JourneyPatternSection JPS) { return InsertBefore(JPS, Count); } 
} 

正如你所看到的,什麼是不同的類型(JourneyPattern,或JourneyPatternSection),和我是前綴用於類型(「JP_」或「JPS_」)的「id」屬性。其他一切都很常見,因爲確定「唯一性」(屬性「散列」)的方法是定製類型的一部分。

我的一些自定義集合需要更多的參與和這些方法的不同實現,這是很好的,但這是最常見的,我已經實現了它大約6次,這似乎是沒有意義的,和b)更難保持。

您的想法和幫助表示讚賞!

+0

讓你的類實現一些包含的接口s屬性「id」和「hash」並且限制到那個接口的類型(class YourCollection :List where T:IYourInterface)。 – Evk

+0

好的,我可以看到如何工作。據推測,我還需要自定義類型來在界面中實現另一個屬性,例如「id_pfx」這樣的集合知道用什麼前綴編號 – StuartR143

+0

是的,還是讓集合本身存儲前綴,就像回答下面的建議。 – Evk

回答

1

Assming塔都JourneyPatternJourneyPatternSection實現公共interface,如:

public interface IJourney 
{ 
    string hash { get; set; } 
    string id { get; set; } 
} 

您可以實現您的收藏一個基類:

public abstract class SpecializedList<T> : List<T> where T : class, IJourney 
{ 
    private Dictionary<string, T> jpHashes;  // This is a hash table for quick lookup of a JP based on its values 

    protected abstract string IdPrefix { get; } 

    /* Add a journey pattern to the JourneyPatterns collection. Three methods for adding: 
      1. "Insert Before" (=at) a particular point in the list. This is the method used by all three methods. 
      2. "Insert After" a particular point in the list. This is "before" shifted by 1 e.g. "after 6" is "before 7" 
      3. "Append" to the end of the list. This is "before" with a value equal to the list count, and is the same as inherited "Add", but with checks 
    */ 
    public T InsertBefore(T JP, int before) 
    { 
     // check for a pre-existing JP with the same parameters (ignore ID). Do this by constructing a "key" based on the values to check against 
     // and looking it up in the private hash dictionary 
     T existingJP; 
     if (jpHashes.TryGetValue(JP.hash, out existingJP)) { return existingJP; } 
     else 
     { 
      // construct a new ID for this JP 
      if (string.IsNullOrWhiteSpace(JP.id)) JP.id = "JP_" + (Count + 1).ToString(); 
      // next check that the ID specified isn't already being used by a different JPS 
      if (Exists(a => a.id == JP.id)) JP.id = IdPrefix + (Count + 1).ToString(); 
      // now do the add/insert 
      if (before < 0) { Insert(0, JP); } else if (before >= Count) { Add(JP); } else { Insert(before, JP); } 
      // finally add to the hash table for fast compare/lookup 
      jpHashes.Add(JP.hash, JP); 
      return JP; 
     } 
    } 
    public T InsertAfter(T JP, int after) { return InsertBefore(JP, after + 1); } 
    public T Append(T JP) { return InsertBefore(JP, Count); } 
} 

然後實現每個集合:

public class JourneyPatterns : SpecializedList<JourneyPattern> 
{ 
    protected override string IdPrefix => "JP_"; 
} 

public class JourneyPatternSections : SpecializedList<JourneyPatternSection> 
{ 
    protected override string IdPrefix => "JPS_"; 
} 
+0

不幸的不是。 JourneyPatterns包含JourneyPatternSections(其中包含JourneyPatternTimingLinks),但沒有共同的祖先。但感謝 - 整潔的解決方案,否則。 – StuartR143

+0

您可以使用「接口」代替共同的祖先。 –

+0

啊哈!感謝編輯顯示'interface'的實現。這非常出色 - 正是我需要的,並且給了我一個使用接口和抽象的好例子。 – StuartR143

相關問題