2012-01-27 32 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

相关问题