聚合:類之間的一種引用,表示兩個對象之間是整體和部分的弱關係,部分的生命週期可以超過整體,如電腦和鼠標;
組合:表示兩個對象之間是整體和部分的強關係,部分的生命週期不能超越整體,如人和眼睛。
聚合關係的部分,可以在構造器中通過參數傳遞的形式進行初始化,有時聚合比繼承好用。
下面代碼例子就是很好的解釋:
public interface Moveable {
void move();
}
import java.util.Random;
public class Tank implements Moveable {
@Override
public void move() {
System.out.println("Tank Moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
現在我們想在調用move()方法時候,計算一下它的運行時間,一種解決辦法是用繼承,繼承Tank這個類,重寫move()方法。
public class Tank2 extends Tank{
@override
public void move(){
long start = System.currentTimeMillis();
super.move();
long end = System.currentTimeMillis();
System.out.println("time:" + (end-start);
}
}
當我想在調用move()方法時再調用一段話,又要寫Tank3繼承Tanks2並重寫move()方法,但是我想先調用Tank3的方法,再調用Tank2的方法,則又要重寫,當組合多了的時候,任意組合順序則顯得極爲困難,一個好的解決辦法就是用聚合。
public class TankTimeProxy implements Moveable{
Moveable target;
public TankTimeProxy (Moveable target) {
super();
this.target = target;
}
@Override
public void move() {
long start = System.currentTimeMillis();
System.out.println("starttime:" + start);
target.move();
long end = System.currentTimeMillis();
System.out.println("time:" + (end-start));
}
}
public class TankLogProxy implements Moveable{
Moveable target;
public TankTimeProxy (Moveable target) {
super();
this.target = target;
}
@Override
public void move() {
System.out.println("Tank Start...");
target.move();
System.out.println("Tank Stop...");
}
}
如此便實現了兩種不同的邏輯添加,下面我們來看測試代碼:
public class Client {
public static void main(String[] args){
Tank t = new Tank();
//方式1:先打印時間,再打印日誌
//TankTimeProxy ttp = new TankTimeProxy (t);
//TankLogProxy tlp = new TankLogProxy (ttp);
//方式1:先打印日誌,再打印時間
TankLogProxy tlp = new TankLogProxy (t);
TankTimeProxy ttp = new TankTimeProxy (tlp);
Moveable m = ttp;
m.move();
}
}
上面非常巧妙的進行了兩種組合,有再多的限制條件,都可以用這種方法任意組合,程序更加容易維護。這實際是一種靜態代理模式。