2012-01-27 69 views
2

這次,我要創建一個數學問題。我計劃有一本字典,關鍵是Levels enum {Easy,Medium,Hard},值應該包含關於如何創建問題的一些配置。留下一個空的界面是一個好的做法嗎?

例如:

BinaryProblemConfiguration 
    + Bound1 : Bound<int> 
    + Bound2 : Bound<int> 

束縛具有兩個屬性:min和max。

其他類型的問題不需要界限,但需要其他數據。

所以,我在想創建一個名爲IConfiguration的接口。

public interface IConfiguration {} 

而具體的配置應該是:

public class BinaryProblemConfiguration : IConfiguration 
{ 
    public Bound Bound1 {get;set;} 
    public Bound Bound2 {get;set;} 
} 

public class AnotherProblemConfiguration : IConfiguration 
{ 
    // other stuff 
} 

的想法是有一個叫ConfigurationLevels字典。這是一個很好的做法,將界面留空或者意味着我的設計有問題嗎?

+0

如果您確定界面永遠不會有任何方法,它的用途是什麼?如果它只是將某個類標記爲某個「類型」,請使用屬性。 – millimoose 2012-01-27 20:44:32

+0

請參閱http://en.wikipedia.org/wiki/Marker_interface_pattern – nulltoken 2012-01-27 20:45:13

+1

C#中的屬性和Java中的註釋提供了用於元數據的手段,使「標記接口」不再顯示。 – diggingforfire 2012-01-27 21:10:40

回答

8

.NET框架設計指南將此稱爲「標記」界面,並且明確表示這不是一個好主意。他們推薦使用自定義屬性來代替。

避免使用標記接口(沒有成員的接口)。

自定義屬性提供了一種標記類型的方法。有關自定義屬性的更多信息 ,請參閱編寫自定義屬性。如果可以推遲檢查屬性 直到代碼執行,則首選自定義 屬性。如果您的方案需要編譯時間 檢查,則無法遵守本指南。

http://msdn.microsoft.com/en-us/library/ms229022.aspx

public sealed class ConfigurationAttribute : Attribute { 

} 


[ConfigurationAttribute] 
public class AnotherProblemConfiguration : IConfiguration 
{ 
    // other stuff 
} 
+0

我對如何聲明它有點困惑?你能告訴我如何改變它嗎? – 2012-01-27 20:49:12

+0

查看我最近的修改。 – 2012-01-27 20:55:37

+0

P.S.此規則僅適用於專業級圖書館。如果您爲自己或公司盜用了某些東西,則可以使用標記界面。 – 2012-01-27 20:57:29

2

你會在哪裏本身使用的IConfiguration一個實例?如果有這樣的用例:

void Something(IConfiguration configuration) { ... } 

然後是的,它很好。但是,一個空的界面,這將是一個有趣的用例。隨口說說,出現在腦海的一個序列化對象,你知道該對象通過該方法進行序列化必須是一個IConfiguration,但你實際上並不關心什麼IConfiguration樣子:

void SerializeConfiguration(IConfiguration configuration) { ... } 

現在從純粹的功能角度來看,這與Object一樣好,但我認爲這是一種合理的方式,它提供了一種編譯時機制,強烈建議有人不使用此方法序列化任何配置,而只是配置。

這些標記接口的另一個常見用法是使用反射來查找通過實現通用接口「標記」的類型。

+0

我會重新說'有趣'爲'壞'。一個空的界面與它的目的相矛盾。正如Jonathan Alles指出的那樣,這就是屬性的原因。 – diggingforfire 2012-01-27 20:51:19

+0

啊,但檢查一個對象是否有接口比檢查對象的類型是否具有屬性要快得多。 – 2012-01-27 20:58:25

+0

@diggingforfire我可以想到至少有一個用例,其中一個空接口是有用的...我會相應地編輯。 – 2012-01-27 21:05:01

1

擁有一個擴展另一個接口但不增加任何內容的接口絕對有用。例如,可以輕鬆想象從IEnumerable<T>繼承的IImmutableEnumerable<T>的用例,但承諾其返回的項目序列不會因任何原因而發生更改。需要具有不會改變的項目列表的例程可能具有IEnumerable<T>IImmutableEnumerable<T>的超負荷。第一個重載可以檢查提供的對象實例是否實現IImmutableEnumerable<T>,如果不是,則通過複製原始項中的項來生成新的不變列表;第二個重載可以直接使用傳入的列表,因爲實現IImmutableEnumerable<T>是已知的。

想象一下根本沒有任何成員的接口的用例有點難以想象。這種接口可以用在約束中以允許例程接受不具有其他公共基類型的各種類型,但不幸的是,類層次足夠複雜以使得這種概念上有用的事物使得難以持久滿足這些約束的對象。

+0

這種合同變更是否違反了[LSP](http://en.wikipedia.org/wiki/Liskov_substitution_principle) ? – 2014-12-01 10:32:16

+0

接口'IEnumerable '承諾枚舉請求會產生一些序列。它沒有承諾持有對實現的引用的代碼是否可以使用該引用來修改序列,也沒有承諾所有將來的枚舉請求都會產生相同的序列。如果'IImmutableEnumerable '(衍生自'IEnumerable ')承諾所有未來的枚舉都會產生相同的序列,這樣的承諾不會抵觸任何'IEnumerable '的承諾。請注意,許多'IEnumerable '...... – supercat 2014-12-01 17:45:27

+0

......的實現不能合法地實現'IImmutableEnumerable ',因爲它們不能保證所有將來的枚舉都會返回相同的結果。還要注意,沒有實現「IImmutableEnumerable 」的類型,也沒有任何類型可以合法地提供任何改變由此封裝的序列的手段。'IEnumerable '的許多合法實現不會實現'IImmutableEnumerable '不是LSP違規;派生的接口*預計*對*實現者施加新的要求* - 僅僅不在*消費者*上。 – supercat 2014-12-01 17:48:46

相關問題