這也許措辭不當。這不是關於類型,而是行爲。當你偏愛合成而不是繼承時,行爲可以在運行時動態地改變 - 當你將它與不限制你的類型層次結構的接口相匹配時,它的效果會更好。
考慮標準:
interface Painter {
public String getName();
public void paint(Canvas c);
}
class Canvas {
@Override
public String toString() {
return "a canvas.";
}
}
class NouveauPainter implements Painter {
public void paint(Canvas c) {
System.out.printf "%s Painted a nouveau stroke on %s.\n",
getName(),
c);
}
public String getName() {
return getClass().getSimpleName();
}
}
class ClassicPainter implements Painter {
public void paint(Painter p, Canvas c) {
System.out.printf "%s Painted a classic stroke on %s.\n",
getName(),
c);
}
public String getName() {
return getClass().getSimpleName();
}
}
public class DoSomePainting() {
public static void main(String...args) {
Canvas c = new Canvas();
Painter oldschool = new ClassicPainter();
oldschool.paint(c);
Painter newschool = new NouveauPainter();
oldschool.paint(c);
}
}
你必須選擇一個類型的畫家或其他的。但是如果你想在運行時改變筆畫呢?這通常是必要的。如果將paint方法嵌入到父類(或抽象類)中,那麼如果要重用功能並可能最終產生各種抽象抽象和神類,則會被卡在類型層次結構中。考慮follwing:
interface Stroke {
public void paint(Painter p, Canvas c)
}
class ClassicStroke {
public void paint(Painter p, Canvas c) {
System.out.printf "%s Painted a classic stroke on %s.\n",
p.getName(),
c);
}
}
class NouveauStroke {
public void paint() {
System.out.printf "%s Painted a nouveau stroke on %s.\n",
p.getName(),
c);
}
}
class GenericPainter implements Painter {
public Stroke stroke = null;
public void paint(Canvas c) {
stroke.paint(this, c);
}
public String getName() {
return getClass().getSimpleName();
}
}
public class DoSomePainting() {
public static void main(String...args) {
Canvas c = new Canvas();
Painter versatile = new GenericPainter();
versatile.stroke = new ClassicStroke();
versatile.paint(c);
versatile.stroke = new NouveauStroke();
versatile.paint(c);
}
}
現在畫家的定義,它的執行部件,被明確區分,可以重新用於任何地方。
注意:我不確定這是否全部編譯 - 這是更多的說明目的和文本框中的編碼是尷尬的。
然後使用合成,你可以,然後,例如,基於配置文件或其他發生在系統中(或玩,堅持域語言),改變哪種類型的演員正在執行 –
怎麼可能'階段'永遠延長'HappyActor'? –
問題在於組合如何提供動態類型,而不是繼承。這只是一個例子,其他方式如何,使用提供的類 –