当前位置: 首页 > 知识库问答 >
问题:

Liskov替代原理VS接口隔离原理

弘康安
2023-03-14

我在理解这两个原则时有些困难。这是一个有点长的阅读问题,所以要有耐心。

假设我们有一个类

abstract class Shape {
    abstract void onDraw();
}

和接口

interface SideCountable {
  int getSidesCount();
}

然后我们创建了两个子类

class Quad extends Shape {

   @Override
   public void onDraw() {
   //some draw logic here
   }
}

class Triangle extends Shape {

   @Override
   public void onDraw() {
   //some draw logic here
   }
}

现在我们将使ShapeimplementsSideCountable

abstract class Shape implements SideCountable{
    abstract void onDraw();
}

并在儿童课程中做出改变

class Quad extends Shape {

   @Override
   public int getSidesCount() {
       return 4;
   }

   @Override
   public void onDraw() {
   //some draw logic here
   }
}

class Triangle extends Shape {

   public int getSidesCount() {
       return 3;
   }

   public void onDraw() {
   //some draw logic here
   }
}

并为该结构创建测试函数(如下LSP):

public void printSidesCount(List<Shape> shapes) {
    for(int i=0; i < shapes.size(); i++) {
        System.out.println(shapes.get(i).getSidesCount());
    }
}

在这里我想停下来,因为实际上在下一步我被绊倒了。如果我们要创建第三个类

class Circle extends Shape {

   public int getSidesCount() {
       return ???;
   }

   @Override
   public void onDraw() {
   //some draw logic here
   }
}

圆没有边,所以为这个孩子实现SideCountable听起来很可笑。好的,我们可以只将实现移到四边形和三角形,但在这种情况下LSP将不再工作。有人能描述一下我该怎么做?

  • SideCountable留在Shape类中,并为Circle返回0并打破接口隔离原则?
  • SideCountable移动到Quad三角形并打破LSP原则?

共有1个答案

申黎明
2023-03-14

首先,您的方法printsidescont只需要知道列表包含SideCountable对象。所以给它的参数类型列表

public void printSidesCount(List<SideCountable> sideCountables) {
    for(int i=0; i < (); i++) {
        System.out.println(sideCountables.get(i).getSidesCount());
    }
}

或者甚至List

public void printSidesCount(List<? extends SideCountable> sideCountables) {
    for(int i=0; i < sideCountables.size(); i++) {
        System.out.println(sideCountables.get(i).getSidesCount());
    }
}

如果不是所有形状都有可计数的边数,那么类Shape不应该实现接口SideCountable。相反,除了扩展类Shape之外,还要使类QuadTriangle实现接口SideCountable

class Quad extends Shape implements SideCountable {
    // ...
}

class Triangle extends Shape implements SideCountable {
    // ...
}

并使类圆形扩展形状,但不实现侧可数

class Circle extends Shape { // Not SideCountable
    // ...
}

当您这样做时,类型系统将帮助您:

  • 你可以通过一个List

 类似资料:
  • 我试图通过反复阅读维基百科条目来确定我对上述原则的理解。 撇开仍然让我悲伤的协变和逆变的概念不谈,wikipedia还提到超类型的不变量必须保留在子类型和历史约束或历史规则中。基于最后两个概念,我提出了一个小例子: 所以我的问题是:基于上述两个概念,我用这个例子是否违反了原则?若否,原因为何? 事先非常感谢。

  • Liskov替代原则(LSP)和界面分离原则(ISP)之间有什么核心区别吗?最终,这两种方法都是为了设计具有通用功能的界面,并在您具有特殊功能时引入新的界面。

  • 来自维基百科, Liskov的行为子类型概念定义了对象的可替代性概念;也就是说,如果S是T的子类型,则程序中T类型的对象可以替换为S类型的对象,而不改变该程序的任何期望属性(例如正确性)。 假设以下类层次结构: 基本抽象类-。它有一个只读属性,在后继程序中被重写。 基类的继承者-,它重写并返回灰色。 Cat的继任者-,它覆盖并返回带条纹的。 然后我们声明一个方法,参数类型为(不是)。 向该方法发送

  • 简介 接口隔离原则(英语:interface-segregation principles, 缩写:ISP)指明没有客户(client)应该被迫依赖于它不使用方法。接口隔离原则(ISP)拆分非常庞大臃肿的接口成为更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。这种缩小的接口也被称为角色接口(role interfaces)。接口隔离原则(ISP)的目的是系统解开耦合,从而容易重构,更

  • 假设我有一个抽象类鸟,它的一个函数是飞(int高度)。 我有许多不同的鸟类,每个类都有自己不同的飞的实现,这个函数在整个应用程序中被广泛使用。 有一天,我的老板来了,要求我添加一只鸭子,它做其他鸟类所做的一切,只是它不飞,而是在应用程序的池塘里游泳。 将duck添加为bird的子类型违反了Liskov替换规则,因为在调用duck时。我们要么抛出异常,要么什么也不做,要么违反正确性原则。 在牢记坚实