2. Liskov Substitution Principle(LSP)の
定義:基本クラスへのすべての参照は、サブクラスオブジェクトを透過的に使用できる必要があります。Liskov Substitution Principle
:つまり、オブジェクトがプログラム内のサブクラスに置き換えられた場合このとき、プログラムは元の動作を継続でき、ルーンとサブクラスの違いを検出できません。しかし、その逆は成り立ちませんプログラムがサブクラスを使用する場合、それは必ずしも親クラスに適用できるわけではありません。
例としてコンピューターを取り上げます。コンピューターにはCPUがあり、コンピューターはプログラムエンティティであり、CPUはそれが使用する基本クラスであり、CPUにはサブクラスIntelCpuがあります。
public class Cpu {
public void work(){
System.out.println( "CPU在工作" );
}
}
public class IntelCpu extends Cpu {
@Override
public void work(){
System.out.println( "英特尔CPU工作" );
}
}
public class Computer {
private Cpu cpu;
public void run(){
this .cpu.work();
}
public Cpu getCpu(){
return cpu;
}
public void setCpu(Cpu cpu){
this .cpu = cpu;
}
}
コンピューターは親クラスに依存します。このとき、CPUはIntelタイプに置き換えられ、コンピューターは正常に動作しますが、Liskov置換の原則に沿った変更には気付きません。
そして逆に、現在コンピュータがあるとすると、それはIntelCpuでのみ機能します。
パブリック クラスIntelCpuComputer {
private IntelCpu cpu;
public void run(){
this .cpu.work();
}
public IntelCpu getCpu(){
return cpu;
}
public void setCpu(IntelCpu cpu){
this .cpu = cpu;
}
}
この時点でIntelCpuを親CPUに置き換えると、コンピューターはIntelCpuを使用する場合にのみ正しく動作するため、正しく動作しません。
public static void main(String [] args){
IntelCpuComputer computer = new IntelCpuComputer();
computer.setCpu(new Cpu()); // 报错
}
別の例として、正方形は数学では特別な長方形であることは誰もが知っていますが、正方形は長方形のサブクラスと言えるでしょうか。
正方形と長方形を表すためにコードを使用します:
/ **
*长方形
* @author ZhaoShuai
* @date 2020/4/12に作成
* * /
public class Rectangle {
private Integer height;
プライベート整数幅。
public Integer getHeight(){
高さを返す;
}
public void setHeight(Integer height){
this .height = height;
}
public Integer getWidth(){
幅を返す;
}
public void setWidth(Integer width){
this.width = 幅;
}
}
/ **
*正方形
* @author ZhaoShuai
* @date 2020/4/12に作成
* * /
public class Square {
private Integer side;
public Integer getSide(){
戻り側;
}
public void setSide(Integer side){
this .side = side;
}
}
サブクラスを抽出することで親クラスがカプセル化されていることは誰もが知っています。上記のコードから、長方形と正方形の構造式が異なることがわかります。長方形には長さと幅の属性があり、正方形には可変長の属性があります。
したがって、正方形は長方形のサブクラスではありません。もちろん、長方形を親クラスとして継承するように強制することもできますが、継承のために継承することはできません。このような継承のための継承は、リスコフの代替原則の一部ではありません。
パッケージcom.xiazhi.principle.lsp;
/ **
* @author ZhaoShuai
* @date 2020/4/12に作成
* * /
public class SquareExtendsRectangle extends Rectangle {
private Integer side;
@Override
public void setHeight(Integer height){
this .setSide(height);
}
@Override
public void setWidth(Integer width){
this .setSide(width);
}
@Override
public Integer getHeight(){
これを返す .getSide();
}
@Override
public Integer getWidth(){
return this .getSide();
}
public Integer getSide(){
return side;
}
public void setSide(Integer side){
this .side = side;
}
}
四角形から四角形を強制的に継承し、次にテストクラスを記述していることがわかります。
public static void main(String [] args){
System.out.println( "============长方形==============" );
長方形長方形 = 新しい長方形();
polygon.setHeight( 10 );
polygon.setWidth( 20 );
print(rectangle);
System.out.println( "============正方形==============" );
Rectangle square = new SquareExtendsRectangle();
square.setHeight( 10 );
印刷(正方形);
}
プライベート 静的 voidprint(Rectangle Rectangle){
System.out.println( "高:" + rectangle.getHeight());
System.out.println( "宽:" + レクタングル .getWidth ());
}
テストの結果、正常に動作しているように見えました。現時点では、別のメソッドを追加しています。
public static void main(String [] args){
System.out.println( "============长方形==============" );
長方形長方形 = 新しい長方形();
polygon.setHeight( 10 );
polygon.setWidth( 20 );
テスト(長方形);
System.out.println( "============正方形==============" );
Rectangle square = new SquareExtendsRectangle();
square.setHeight( 10 );
テスト(正方形);
}
プライベート 静的 voidprint(Rectangle Rectangle){
System.out.println( "高:" + rectangle.getHeight());
System.out.println( "宽:" + レクタングル
.getWidth ());
} プライベート 静的 void test(Rectangle長方形){
while(rectangle.getWidth()> = rectangle.getHeight()){
rectangle.setHeight(rectangle.getHeight() +1 );
print(rectangle);
}
}
実行後、長方形は正常に実行できることがわかりますが、正方形には無限ループがあるため、これはLiskov置換の原理と一致していません。サブクラスオブジェクトは、親クラスが参照されている場所では使用できないためです。
クラスの設計では、依存関係の逆転の原則に従って、抽象クラスまたはインターフェースを使用する必要があります。抽象クラスまたはインターフェースを使用できない場合、設計はリスコフ置換原則(LSP)に違反しています。