【问题标题】:Which SOLID Principles are violated?违反了哪些 SOLID 原则?
【发布时间】:2015-06-03 09:52:58
【问题描述】:

简介


我正在写关于继承问题的硕士论文并解决了一些问题 指示存在继承问题的指标。

像下面的例子:

示例


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

如果给定的 Animal 实例是 Dog,则该方法返回字符串 "Woof",如果是 Cat,则返回 "Miau"。空弦,因为有些动物根本不发出声音。

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

我分析了继承问题的不同指标,想说如果 其中一些违反了SOLID Principle

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

  1. 单一责任原则 (SRP)
  2. 开闭原则 (OCP)
  3. 里氏替换原则 (LSP)
  4. 依赖倒置原则(DIP)

但我不确定这是否适用于所有人。

我想:

违反原则


SRP 违规

因为条件语句完全违反了SRP,因为像switch case 语句或多个 if-else 语句被认为是多个责任。

存在两种情况,所以改变方法的理由不止一个。

OCP 违规

因为如果添加了新动物,则必须将新案例添加到方法中 因此该方法不适合修改。

LSP 违规

每个分支根据动物子类型执行不同的操作。 我认为这违反了 LSP ?! 我知道矩形和正方形以及 getArea 的示例,但是这些 我认为也适合违规的示例。

DIP 违规

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

问题:


所以问题是,对于给定的例子,给定的原则是否真的被违反了,推理是否正确?

【问题讨论】:

  • 这可能是 Programmers.SE 上的更多主题。

标签: oop inheritance solid-principles design-principles


【解决方案1】:

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

我强烈反对。 SRP 意味着用少许盐来解释。阅读Uncle Bob's article on it here - 他创造了这个原则。

我将引用重要的部分:

什么定义了改变的理由?

这个原则是关于人的。

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

[...] 当你思考这个原则时,请记住改变的原因是人。是人要求改变。而且您不希望通过将许多不同人出于不同原因而关心的代码混合在一起来混淆这些人或您自己。


OCP因为如果添加新动物,则必须将新案例添加到方法中,因此方法不会关闭以进行修改。

正确。该方法假定了一组特定的实现,如果不进行修改,将无法处理新的实现。


LSP 每个分支根据动物子类型执行不同的操作。我认为这违反了 LSP 吗?!

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


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

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


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

【讨论】:

  • 我要添加 DIP:该方法应该依赖于 MakesNoiseInterface 而不是具体的类。
  • @deceze 不需要接口,抽象已经存在:Animal。问题是针对特定动物的类型检查,我个人会通过将getNoise 方法移动到Animal 中来解决它,解决所有3 个违规问题。
  • 非常感谢您的快速答复!对于 SRP,我认为您错了,请参阅 Robert C. Martin 的书清洁代码网站 38 >此功能存在几个问题。首先,它很大,当添加新的员工类型时,它会增长。其次,它非常清楚地做了不止一件事。第三,它违反了单一职责原则 7 (SRP),因为改变的原因不止一个。这里是干净的代码参考:cleansourcecode.files.wordpress.com/2013/10/clean-code.pdf
  • @Zelldon Robert C. Martin Bob叔叔,我提到过他的文章^^我认为改变的理由不止一个。牢记这篇文章,您能否说出两个或更多改变的原因,来自不同部门/不同业务需求的不同人员?
  • 我知道他是。假设你想改变狗的噪音,一个原因是我,第二个原因是猫的噪音要改变,第三个原因是动物不应该为类似的噪音返回一个空字符串。
【解决方案2】:

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

设 Φ(x) 是关于 T 类型的对象 x 的可证明性质。那么 Φ(y) 对于 S 类型的对象 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。

【讨论】:

  • 谢谢。其他原则呢?
猜你喜欢
  • 2018-11-13
  • 2013-01-01
  • 2010-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多