OO原则:c#:设计界面而不是具体类

时间:2011-08-27 00:23:40

标签: oop design-patterns factory

我对使用具体类和接口的影响有一些疑问。

  1. 说一些代码(称之为chunkCode)使用具体的类A。如果符合以下条件,我是否需要重新编译chunkCode

    1. 我向A添加了一些新的公开方法?如果是这样,是不是有点st?毕竟我仍然提供接口chunkCode所依赖的。 (或者我必须重新编译,因为chunkCode可能永远不会知道这是真的,我没有省略某些API)
    2. 我向A添加了一些新的私有方法?
    3. 我向A添加了一个新的公共字段?
    4. 我向A添加了一个新的私人字段?
  2. 工厂设计模式: 主代码不关心对象的具体类型。它仅依赖于API。但是,如果只有少数方法只与一种具体类型相关,那么你会怎么做?这种类型实现了接口,但增加了一些公共方法?你会使用一些if (A is type1)语句(或类似的)主代码吗?

  3. 感谢您的任何澄清

3 个答案:

答案 0 :(得分:4)

1)编译不是OO中的活动。它是特定OO实现的细节。如果您想要特定实现的答案(例如Java),那么您需要澄清。

一般来说,有人会说添加到界面不会被认为是一个重大变化,其他人说,一旦发布界面就无法更改界面,并且你必须创建一个新的界面。

修改:您指定了C#,因此请查看this question regarding breaking changes in .Net。我不想那样做是为了解决这个问题,所以我不打算在这里复制它。

2)人们经常破解他们的设计,但这表明你的设计很糟糕。

好的选择

  • 在界面中创建一个方法,允许您调用自定义行为,但不需要知道该行为是什么。

  • 创建支持新方法的附加接口(和新工厂)。新接口不必继承旧接口,但如果有意义则可以(如果接口之间可以表达is-a关系)。

  • 如果您的语言支持,请使用Abstract Factory pattern,并在具体工厂中利用Covariant Return Types。如果您需要特定的派生类型,请接受具体工厂而不是抽象工厂。

不良选择(反模式):

  • 在接口中添加一个方法,该方法在其他派生类中没有任何作用。

  • 在对派生类没有意义的方法中抛出异常。

  • 向界面添加查询方法,告诉用户是否可以调用某种方法。

除非方法名称足够通用,用户不希望它做任何事情(例如DoExtraProcessing),否则在大多数派生类中添加no-op的方法会破坏该接口定义的契约

例如:某人调用bird.Fly()会期望它实际上做某事。我们知道鸡不能飞。因此,Chicken不是Bird,或Bird不是Fly

添加查询方法对此来说是一种糟糕的解决方法。例如。在界面中添加boolean CanFly()方法或属性。所以抛出异常。他们都没有解决这个类型根本不可替代的事实。查看Liskov Substitution Principle(LSP)。

答案 1 :(得分:0)

对于你的第一个问题,答案是否定的。如果它会那样,那么向后兼容性没有任何意义。只有在制动API时才需要重新编译chunkCode,即删除chunkCode正在使用的某些功能,更改调用约定,修改参数数量,这些事情= =破坏更改。

对于第二个我通常,但只有在我真的必须的时候,在这些情况下使用dynamic_cast

注意我的回答在C ++的上下文中是有效的;我刚看到这个问题与语言无关(在这个时候有点累;如果有人攻击任何人,我会删除答案)。< / p>

答案 2 :(得分:0)

问题1:取决于您所使用的语言。尽管重新编译这两种语言总是更安全。主要是因为chuckCode不知道A里面究竟存在什么。重新编译会刷新它的内存。但它应该在Java中工作而无需重新编译。

问题2:否。编写工厂的整个要点是摆脱if(A是type1)。从维护角度来看,这些if语句很糟糕。

工厂旨在构建类似类型的对象。如果您遇到使用此语句的情况,则该对象与其他类的类型不同。如果您确定它的类型相似并且具有类似的接口。我会在所有具体的基类中编写一个额外的函数,并仅在此基础上实现它。

理想情况下,所有这些具体类都应该有一个共同的抽象基类或一个接口来定义API。除非您正在编写具有此特定类的函数,否则除了您正在编写具有此特定类的函数之外,不应在代码中的任何位置调用此接口中设计的内容。