我在理解这两个原则时有些困难。这是一个有点长的阅读问题,所以要有耐心。
假设我们有一个类
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
}
}
现在我们将使Shape
implementsSideCountable
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原则?首先,您的方法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
之外,还要使类Quad
和Triangle
实现接口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时。我们要么抛出异常,要么什么也不做,要么违反正确性原则。 在牢记坚实