5、Decorate(裝飾者)
描述:動態的給一個對象添加額外的職責,比繼承達到更好的靈活性
好處:某些功能須要用戶動態決定加入方式和時機,裝飾者提供即插即用的模型框架
例子:
舉Adapter中的打樁示例,在Adapter中有兩種類:方形樁 圓形樁,Adapter模式展現如何綜合使用這兩個類,在Decorator模式中,咱們是要在打樁時增長一些額外功能,好比,挖坑 在樁上釘木板等,不關心如何使用兩個不相關的類
咱們先創建一個接口:
public interface Work
{
public void insert();ide
}
this
接口Work有一個具體實現:插入方形樁或圓形樁,這兩個區別對Decorator是無所謂.咱們以插入方形樁爲例:
public class SquarePeg implements Work{
public void insert(){
System.out.println("方形樁插入");
} 設計
}
xml
如今有一個應用:須要在樁打入前,挖坑,在打入後,在樁上釘木板,這些額外的功能是動態,可能隨意增長調整修改,好比,可能又須要在打樁以後釘架子(只是比喻).
那麼咱們使用Decorator模式,這裏方形樁SquarePeg是decoratee(被裝飾者),咱們須要在decoratee上加些"裝飾",這些裝飾就是那些額外的功能.
public class Decorator implements Work{對象
private Work work;
//額外增長的功能被打包在這個List中
private ArrayList others = new ArrayList(); 繼承
//在構造器中使用組合new方式,引入Work對象;
public Decorator(Work work)
{
this.work=work;
others.add("挖坑");接口
others.add("釘木板");
}內存
public void insert(){字符串
newMethod();
}
//在新方法中,咱們在insert以前增長其餘方法,這裏次序前後是用戶靈活指定的
public void newMethod()
{
otherMethod();
work.insert();
}
public void otherMethod()
{
ListIterator listIterator = others.listIterator();
while (listIterator.hasNext())
{
System.out.println(((String)(listIterator.next())) + " 正在進行");
}
}
}
在上例中,咱們把挖坑和釘木板都排在了打樁insert前面,這裏只是舉例說明額外功能次序能夠任意安排.
好了,Decorator模式出來了,咱們看如何調用:
Work squarePeg = new SquarePeg();
Work decorator = new Decorator(squarePeg);
decorator.insert();
Decorator模式至此完成.
若是你細心,會發現,上面調用相似咱們讀取文件時的調用:
FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr);
實際上Java 的I/O API就是使用Decorator實現的,I/O變種不少,若是都採起繼承方法,將會產生不少子類,顯然至關繁瑣.
6、Bridege(橋接)
描述:將抽象和行爲劃分開,各自獨立,但能動態結合
好處:多個concrete class之間有概念上重疊.那麼須要咱們把抽象共同部分和行爲共同部分各自獨立開來,原來是準備放在一個接口裏,如今須要設計兩個接口,分別放置抽象和行爲
例如,一杯咖啡爲例,有中杯和大杯之分,同時還有加奶 不加奶之分. 若是用單純的繼承,這四個具體實現(中杯 大杯 加奶 不加奶)之間有概念重疊,由於有中杯加奶,也有中杯不加奶, 若是再在中杯這一層再實現兩個繼承,很顯然混亂,擴展性極差.那咱們使用Bridge模式來實現它.
如何實現?
以上面提到的咖啡 爲例. 咱們原來打算只設計一個接口(抽象類),使用Bridge模式後,咱們須要將抽象和行爲分開,加奶和不加奶屬於行爲,咱們將它們抽象成一個專門的行爲接口.
先看看抽象部分的接口代碼:
public abstract class Coffee
{
CoffeeImp coffeeImp;
public void setCoffeeImp() {
this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();
}
public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}
public abstract void pourCoffee();
}
其中CoffeeImp 是加不加奶的行爲接口,看其代碼以下:
public abstract class CoffeeImp
{
public abstract void pourCoffeeImp();
}
如今咱們有了兩個抽象類,下面咱們分別對其進行繼承,實現concrete class:
//中杯
public class MediumCoffee extends Coffee
{
public MediumCoffee() {setCoffeeImp();}
public void pourCoffee()
{
CoffeeImp coffeeImp = this.getCoffeeImp();
//咱們以重複次數來講明是衝中杯仍是大杯 ,重複2次是中杯
for (int i = 0; i < 2; i++)
{
coffeeImp.pourCoffeeImp();
}
}
}
//大杯
public class SuperSizeCoffee extends Coffee
{
public SuperSizeCoffee() {setCoffeeImp();}
public void pourCoffee()
{
CoffeeImp coffeeImp = this.getCoffeeImp();
//咱們以重複次數來講明是衝中杯仍是大杯 ,重複5次是大杯
for (int i = 0; i < 5; i++)
{
coffeeImp.pourCoffeeImp();
}
}
}
上面分別是中杯和大杯的具體實現.下面再對行爲CoffeeImp進行繼承:
//加奶
public class MilkCoffeeImp extends CoffeeImp
{
MilkCoffeeImp() {}
public void pourCoffeeImp()
{
System.out.println("加了美味的牛奶");
}
}
//不加奶
public class FragrantCoffeeImp extends CoffeeImp
{
FragrantCoffeeImp() {}
public void pourCoffeeImp()
{
System.out.println("什麼也沒加,清香");
}
}
Bridge模式的基本框架咱們已經搭好了,別忘記定義中還有一句:動態結合,咱們如今能夠喝到至少四種咖啡:
1.中杯加奶
2.中杯不加奶
3.大杯加奶
4.大杯不加奶
看看是如何動態結合的,在使用以前,咱們作個準備工做,設計一個單態類(Singleton)用來hold當前的CoffeeImp:
public class CoffeeImpSingleton
{
private static CoffeeImp coffeeImp;
public CoffeeImpSingleton(CoffeeImp coffeeImpIn)
{this.coffeeImp = coffeeImpIn;}
public static CoffeeImp getTheCoffeeImp()
{
return coffeeImp;
}
}
看看中杯加奶 和大杯加奶 是怎麼出來的:
//拿出牛奶
CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp());
//中杯加奶
MediumCoffee mediumCoffee = new MediumCoffee();
mediumCoffee.pourCoffee();
//大杯加奶
SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();
superSizeCoffee.pourCoffee();
7、Flyweight(享元)
描述:運用共享技術有效的支持大量細粒度的對象
好處:避免大量擁有相同內容的小類的開銷(如耗費內存),使你們共享一個類(元類).
當大量從數據源中讀取字符串,其中確定有重複的,那麼咱們使用Flyweight模式能夠提升效率,以唱片CD爲例,在一個XML文件中,存放了多個CD的資料.
每一個CD有三個字段:
1.出片日期(year)
2.歌唱者姓名等信息(artist)
3.唱片曲目 (title)
其中,歌唱者姓名有可能重複,也就是說,可能有同一個演唱者的多個不一樣時期 不一樣曲目的CD.咱們將"歌唱者姓名"做爲可共享的ConcreteFlyweight.其餘兩個字段做爲UnsharedConcreteFlyweight.
首先看看數據源XML文件的內容:
<?xml version="1.0"?>
<collection>
<cd>
<title>Another Green World</title>
<year>1978</year>
<artist>Eno, Brian</artist>
</cd>
<cd>
<title>Greatest Hits</title>
<year>1950</year>
<artist>Holiday, Billie</artist>
</cd>
<cd>
<title>Taking Tiger Mountain (by strategy)</title>
<year>1977</year>
<artist>Eno, Brian</artist>
</cd>
.......
</collection>
雖然上面舉例CD只有3張,CD可當作是大量重複的小類,由於其中成分只有三個字段,並且有重複的(歌唱者姓名).
CD就是相似上面接口 Flyweight:
public class CD {
private String title;
private int year;
private Artist artist;
public String getTitle() { return title; }
public int getYear() { return year; }
public Artist getArtist() { return artist; }
public void setTitle(String t){ title = t;}
public void setYear(int y){year = y;}
public void setArtist(Artist a){artist = a;}
}
將"歌唱者姓名"做爲可共享的ConcreteFlyweight:
public class Artist {
//內部狀態
private String name;
// note that Artist is immutable.
String getName(){return name;}
Artist(String n){
name = n;
}
}
再看看Flyweight factory,專門用來製造上面的可共享的ConcreteFlyweight:Artist
public class ArtistFactory {
Hashtable pool = new Hashtable();
Artist getArtist(String key){
Artist result;
result = (Artist)pool.get(key);
////產生新的Artist
if(result == null) {
result = new Artist(key);
pool.put(key,result);
}
return result;
}
}
當你有幾千張甚至更多CD時,Flyweight模式將節省更多空間,共享的flyweight越多,空間節省也就越大