违反了哪些SOLID原则?

时间:2015-06-03 09:52:59

标签: oop inheritance solid-principles design-principles

引言

我正在研究关于继承问题的硕士论文,并研究出一些问题 表明存在遗传问题的指标。

如以下示例所示:

示例

public static String getAnimalNoise(Animal animal) {
  if (animal instanceof Dog)
    return "Woof";
  if (animal instanceof Cat)
    return "Miau";
  return "";
}

如果给定的Animal实例是"Woof",则该方法返回String Dog,如果是"Miau",则返回Cat。空绳子,因为有些动物根本没有噪音。

因此,正确的解决方案应该是使用多态与Animal类中的getNoise方法。

我已经分析了继承问题的不同指标,并想说是否 其中一些违反了SOLID Principle

我认为上面的例子违反了:

  1. 单一责任原则(SRP)
  2. 开放/封闭原则(OCP)
  3. Liskov替换原则(LSP)
  4. 依赖性倒置原则(DIP)
  5. 但我不确定这是否适用于所有人。

    我想:

    违反原则

    SRP违规行为

    因为条件语句完全违反 SRP ,因为像开关一样 案例陈述或多个if-else陈述都要考虑多个责任。

    存在两种情况,因此更改方法的原因不止一个。

    OCP违规行为

    因为如果添加新动物,必须在方法中添加新案例 所以方法并不接近修改。

    LSP VIOLATION

    每个分支执行依赖于动物子类型的不同动作。 我认为违反了 LSP ? 我知道矩形和正方形的例子以及getArea但这些 我认为也适用于违规的例子。

    DIP VIOLATION

    条件语句具有依赖性,这意味着语句依赖于细节,而不依赖于违反 DIP 的抽象。

    问题:

    因此,对于给定的例子,问题是否真的违反了给定的原则并且推理是否正确?

2 个答案:

答案 0 :(得分:8)

  

SRP 因为条件语句完全违反了SRP,因为像switch case语句或多个if-else语句一样会考虑多个责任。   它存在两种情况,因此改变方法的原因不止一个。

我非常不同意。 SRP旨在用少量的盐来解释。阅读Uncle Bob's article on it here - 他创造了这个原则。

我引用重要的一些内容:

  

什么定义了改变的理由?

     

这个原则是关于人的。

     

当您编写软件模块时,您希望确保在请求更改时,这些更改只能来自一个人,或者更确切地说,来自一个紧密耦合的人群,代表一个狭义的业务功能。您希望将模块与整个组织的复杂性隔离开来,并设计您的系统,使每个模块负责(响应)仅一个业务功能的需求。

     

[...]当你想到这个原则时,请记住改变的原因是人。是要求变更的人。而且你不想把这些人或者你自己混淆在一起,将不同人所关心的代码混合在一起。

  

OCP 因为如果添加新动物,必须在方法中添加新案例,以便方法不会因修改而关闭。

正确。该方法假定一组特定的实现,并且无法在不进行修改的情况下处理新的实现。

  

LSP 每个分支执行依赖于动物子类型的不同动作。我认为违反了LSP?!

它违反了LSP,但原因不同。如果我要传入长颈鹿,我会得到一个意想不到的结果,一个空字符串。这意味着该方法对于Animal的任何子类型都不正确。

  

DIP 条件语句具有依赖性,这意味着语句依赖于细节,而不依赖于违反DIP的抽象。

技术上是正确的,但这只是违反上述其他两个原则的副作用。它并不是问题的核心。

请记住,原则不是规则,因此在解释时不要过于严格/字面意思。实用主义和理解为什么需要一个原则是关键。

答案 1 :(得分:2)

我不同意您的示例代码违反LSP的事实。 LSP定义如下:

  

设Φ(x)是关于类型T的对象x可证明的属性。对于S类型的对象y,Φ(y)应该为真,其中S是T的子类型。

鉴于Animal的两个推导,即DogCat以及您的方法getAnimalNoise,您不会对具体对象的某些可证明属性做出决策。你的方法是决定应该返回什么样的噪音而不是那些自己的对象。

因此,假设您可以设置动物的腿数。

Animal a = new Animal()
a.setLegFront(2);
a.setLegRear(2);

如果你的Dog像这样覆盖:

 class Dog extends Animal
 {
   public void setFrontLegs(int legs)
   {
     this.frontLegs = legs;
     this.rearLegs = legs + 2; 
   }
   public void setRearLegs(int legs)
   {
     // do nothing here for demonstration purposes
   }
 }

如果您现在有一家工厂退回Animal

Animal createAnimal()
{
   return new Dog();
}
Animal a = createAnimal();
a.setFrontLegs(2);
a.setRearLegs(2);

你调用方法setFront/setRearLegs你期望结果是2和2,但实际上结果是完全不同的,即2和4.所以这个例子与普通的LSP例子紧密结合和矩形。但对我来说,这是一个比你的例子更可靠的违反可证明属性的例子。

更新其他原则

我同意你的观点,其他原则也被违反,但对于SRP,我同意@dcastro。