1. 程式人生 > >繼承,裝飾者模式和動態代理之間的區別

繼承,裝飾者模式和動態代理之間的區別

Java中,需要對物件進行增強時,我們常用的三種方法是 繼承, 裝飾者模式和動態代理.現在,舉個例子來描述這三者之間的區別.

在星巴克喝咖啡時, 可以選擇各種調味品, 黑咖啡中可以選擇加糖,加奶,加蜂蜜. 這樣咖啡的味道被改變,我們可以說黑咖啡被"增強"了.用java程式碼這樣表示:

/**
* 建立一個咖啡的類,裡面有黑咖啡
*/
class Coffee{
	void blankCoffee(){
		System.out.println("黑咖啡");
	}
}
/**
* 現在要對黑咖啡加糖
*/
class Sugar extends Coffee {
	void blankCoffee() {
		super.blankCoffee();
		System.out.println("加糖");
	}
}
/**
* 現在要對黑咖啡加奶
*/
class Milk extends Coffee {
	void blankCoffee() {
		super.blankCoffee();
		System.out.println("加奶");
	}
}

/**
* 現在要對黑咖啡加蜂蜜
*/
class Honey extends Coffee {
	void blankCoffee() {
		super.blankCoffee();
		System.out.println("加蜂蜜");
	}
}


這樣子我們得到了三種不同口味的黑咖啡. 現在又有了新的問題, 要求要加奶又加糖的咖啡,需要給加奶的咖啡加上糖,用繼承這樣子來實現

/**
* 現在需要加奶加糖咖啡
*/
class SugarMilke extends Milk {
void blankCoffee() {
super.blankCoffee();
System.out.println("加糖");
}
}
...


可能還需要加奶加蜂蜜的咖啡... 多種排列組合就會出現很多類, 出現了新的一種口味又需要增加很多的類.

這時候我們用裝飾者模式來解決這個問題

/**
* 首先定義一個介面來規範咖啡.
*/
interface Coffee {
	void coffee();
}
/*
* 實現這個上面這個介面中的方法.
*/
class CoffeeImpl implements Coffee {
	public void coffee(){
		System.out.println("黑咖啡");
	}
}
/*
* 在給黑咖啡新增調味品之前,我們先定義一個類,這個類是所有新增調味品咖啡的父類,進行包裝
*/
class CoffeeWrapper implements Coffee {
	private Coffee cof;
	public CoffeeWrapper(Coffee cof){
		this.cof = cof;
	}
	public void coffee(){
		cof.coffee();
	}
}

/**
* 加糖咖啡
*/ 
class Sugar extends CoffeeWrapper {
	public Sugar(Coffee cof) {
		super(cof);
	}
	public void coffee(){
		super.coffee();
		System.out.println("加糖");
	}
}
/**
* 加奶咖啡
*/ 
class Milk extends CoffeeWrapper {
	public Milk(Coffee cof) {
		super(cof);
	}
	public void coffee(){
		super.coffee();
		System.out.println("加奶");
	}
}
/**
* 蜂蜜咖啡
*/ 
class Honey extends CoffeeWrapper {
	public Honey(Coffee cof) {
		super(cof);
	}
	public void coffee(){
		super.coffee();
		System.out.println("加蜂蜜");
	}
}
/**
* 演示
*/
public class Demo() {
	public static void main(String[] args) {
		//首先建立一個黑咖啡
		Coffee cof = new CoffeeImpl();
		//加糖咖啡
		Coffee sugar = new Sugar(cof);
		sugar.coffee();
		//加糖又加奶咖啡
		Coffee milk = new Milk(sugar);
		sugar.coffee();
	}
}
這樣我們就解決了這個問題.

* 繼承
  被增強的物件固定的
  增強的內容也是固定的
* 裝飾者模式
  被增強的物件是可以切換的
  增強的內容是固定的

還有一種更加靈活的方式,面向切面程式設計(AOP) ,比裝飾者模式更加靈活, 被增強的物件和增強的內容都是可以更換的.