2016-01-27 107 views
0

我剛剛在(Java)面向對象編程的講座中遇到了Liskov替換原則和鑄造。我明白了原則規定,那就是,我可以初始化一個子類與超類的類型:Liskov替代原則和鑄造

SuperClass superClass = new SubClass(); 

我首先考慮的認爲這樣的操作的目的。爲什麼我不能像往常一樣聲明子類(如下所示)?

SubClass subClass = new SubClass(); 

以後這個權利,我就死在鑄造,具體如下:

SuperClass superClass = new SubClass(); 
SubClass subClass = (SubClass)superClass; 

同樣,我很難理解這一切的地步。

任何人都可以提供任何澄清這些程序的目的嗎?

回答

0

因爲這樣你可以在不知道子類的情況下使用超類方法。考慮下面的例子:

想象的事情由此可以得出:

List<Thing> list = ... 
for(thing: list) { 
    thing.draw() 
} 

現在你想畫:

public abstract class Thing { 
    public abstract void draw(); 
} 

,如果你有這樣的事情的清單,你可以在一個循環中繪製它們實際的東西:圓形,正方形等所以你寫具體的類:

public class Circle extends Thing { 
     private final Point center; 

     public Circle(Point center) { 
      this.center = center; 
     }  

     public void draw() { 
      //draw a circle in coordinates center 
     } 
} 

public class Square... 

你怎麼能創建一個具體事物清單?容易因該超類的子類的概念:

Thing circle1 = new Circle(10,10); 
Thing square = new Square(0,0,10,10); 
Thing circle2 = new Circle(50,100); 

現在將它們添加到列表中,並在相同的循環使用。

List<Thing> list = new ArrayList<>(); 
list.addAll(square, circel1, circle2); 

for(thing: list) { 
    thing.draw() 
} 
1

里氏替換原則意味着,子類應該用理解來完成,你應該只真正關心什麼子類的實例是當它被實例化。從那時起,它應該像超類一樣對待,不需要額外的方法或特殊處理。

這種方法的最大優點是,如果您決定要用另一個子類替換一個子類,那麼您可以!它的調用方式與前一個子類的調用方式完全相同。如果這對你的新子類來說不方便,那麼Liskov會說這意味着它不應該成爲那個超類的子類。應該不分皁白地處理子類。

關於您的演員,當您將SubClass分配給SuperClass時,您現在可以在整個程序中使用一個實例,而不必關心它是否是SubClass。您嘗試將superClass實例轉換回SubClass 的以下行可以執行,但您的可能沒有正確地執行某些操作(同樣,因爲您不應該在意它的子類是什麼)。

一般來說,你會看到一個工廠或方法實例,如下所示:

public SuperClass getSuperClass() { 
    SubClass subClass = new SubClass(); 

    // Here is the only place where you should perform subclass specific 
    // calls. The less you need to do here, the better. 
    subClass.setSubClassProperty(this); 

    return subClass; 
} 

注意隱式轉換爲超類我返回一個子類的實例,主叫方被賦予一個超類的實例。這是我們更喜歡它的方式。調用者可以接收一個SubClass實例,但我們不希望調用者使用SubClass方法。