引入
在看數(shù)據(jù)庫連接池這一章內(nèi)容的時候,出現(xiàn)了面向接口編程和裝飾者模式的設(shè)計模式士修。利用裝飾者設(shè)計模式把數(shù)據(jù)庫連接池接口的實現(xiàn)類(被裝飾者)的close方法重寫(重寫其實也算是一種“添加”)了。
可能從上文很難看得出這是一個什么樣的問題,那么下文便用咖啡的例子幫助大家理解到底裝飾者模式解決了什么問題:
假設(shè)有四種咖啡:HouseBlend盔夜、DarkRoaat、Decaf堤魁、Espresso喂链。
同樣有四種可以搭配的選擇:Milk、Mocha妥泉、Soy椭微、Whip。這四種咖啡有不同的價格盲链、同樣四種搭配也有不同的價格蝇率。當(dāng)我們把這個單子拿給顧客的時候、顧客可以任意點一種咖啡刽沾、可以任意搭配本慕。我們的目的是要統(tǒng)計每種搭配的價格、那我們要寫多少個類侧漓?最后的結(jié)果就是類爆炸锅尘!
當(dāng)我們要添加一個新的品種的時候、如果按照上面的方法布蔗、那我們就要新添加N多類來實現(xiàn)目的藤违。如何有效的解決這兩個問題?也許你有別的很多方法與思想纵揍、這里只是說明裝飾者模式的使用顿乒。
——來源于:Java設(shè)計模式之裝飾者模式
再舉一個例子,也是后面寫程序闡述的:
假設(shè)現(xiàn)在有一個進(jìn)服裝店的人
服裝店里有帽子泽谨、T恤璧榄、裙子
那么用程序來描述:
用Person類描述這個人
如果用繼承方法,
當(dāng)這個人戴上帽子的時候需要一個描述戴帽子的人的子類:HatPerson(繼承Person)
當(dāng)這個人穿上T恤的時候需要一個描述穿T恤的人的子類:TshirtPerson(繼承Person)
當(dāng)這個人穿上裙子的時候需要一個描述穿裙子的人的子類:SkirtPerson(繼承Person)
既戴帽子又穿T恤的時候需要一個描述的子類:HatTshirtPerson(繼承Person或同時繼承HatPerson與TshirtPerson)
......
可以看到隔盛,如果用這樣來描述問題犹菱,非常復(fù)雜拾稳。因為本身“繼承”描述的關(guān)系就是一類事物的細(xì)分吮炕,而不是類似這樣的對事物進(jìn)行某一部分的添油或加醋問題。而很明顯访得,利用“裝飾”這一設(shè)計概念龙亲,可以更靈活的描述這類問題陕凹。
什么是裝飾者模式?
為了更好描述鳄炉,需要對某個類(一個類可以看成描述的一個事物:例如一個人)的某個部分(類中的一個成員杜耙,例如一個人身上穿的衣服)進(jìn)行修改或重寫的這種問題的模式。
啥時候用拂盯?有啥樣的效果佑女?
由上可以總結(jié)出(附上代碼示例):
- 當(dāng)需要對某個類進(jìn)行部分成員變量或方法的時候使用
A Sample
為了更加深刻地理解裝飾者模式,我們來看一個簡單的栗子谈竿。首先团驱,我們假設(shè)現(xiàn)在 有這樣一個需求:你有一家服裝店,賣各式各樣的衣服空凸,現(xiàn)在需要用一個系統(tǒng)來記錄客戶所要購買的衣服的總價嚎花,以便方便地結(jié)算。那么在這個例子里面呀洲,我們可以用裝飾者模式紊选,把客戶當(dāng)做被裝飾者,衣服是裝飾者道逗,這很直觀形象吧兵罢,接著我們來一步步實現(xiàn)需求。Step 1憔辫、創(chuàng)建Component基類
因為總體對象是人趣些,所以我們可以把人抽象為基類,新建Person.java:
public abstract class Person {
String description = "Unkonwn";
public String getDescription()
{
return description;
}
public abstract double cost(); //子類應(yīng)該實現(xiàn)的方法
}
Step 2贰您、創(chuàng)建被裝飾者——ConcreteComponent
客戶分為很多種坏平,有兒童、青少年锦亦、成年人等舶替,因此我們可以創(chuàng)建不同的被裝飾者,這里我們創(chuàng)建青少年的被裝飾者杠园,新建Teenager.java:
public class Teenager extends Person {
public Teenager() {
description = "Shopping List:";
}
@Override
public double cost() {
//什么都沒買顾瞪,不用錢
return 0;
}
}
Step 3、創(chuàng)建Decorator
由于不同的部位有不同的衣物抛蚁,不能混為一談陈醒,比如說,衣服瞧甩、帽子钉跷、鞋子等,那么這里我們創(chuàng)建的Decorator為衣服和帽子肚逸,分別新建ClothingDecorator.java和HatDecorator.java:
public abstract class ClothingDecorator extends Person {
public abstract String getDescription();
}
public abstract class HatDecorator extends Person {
public abstract String getDescription();
}
Step 4爷辙、創(chuàng)建ConcreteDecorator
上面既然已經(jīng)創(chuàng)建了兩種Decorator彬坏,那么我們基于它們進(jìn)行拓展,創(chuàng)建出不同的裝飾者膝晾,對于Clothing栓始,我們新建Shirt.java,對于Hat血当,我們新建Casquette幻赚,其實可以根據(jù)不同類型的衣物創(chuàng)建更多不同的裝飾者,這里只是作為演示而創(chuàng)建了兩種臊旭。代碼如下所示:
public class Shirt extends ClothingDecorator {
//用實例變量保存Person的引用
Person person;
public Shirt(Person person)
{
this.person = person;
}
@Override
public String getDescription() {
return person.getDescription() + "a shirt ";
}
@Override
public double cost() {
return 100 + person.cost(); //實現(xiàn)了cost()方法坯屿,并調(diào)用了person的cost()方法,目的是獲得所有累加值
}
}
public class Casquette extends HatDecorator {
Person person;
public Casquette(Person person) {
this.person = person;
}
@Override
public String getDescription() {
return person.getDescription() + "a casquette "; //鴨舌帽
}
@Override
public double cost() {
return 75 + person.cost();
}
}
- 效果:能夠?qū)悾≒erson)的實例不斷的修改其成員
public class Shopping { public static void main(String[] args) { Person person = new Teenager(); person = new Shirt(person);//對一個person類實例加了T恤 person = new Casquette(person);//對一個person類實例加了帽子 System.out.println(person.getDescription() + " ¥ " +person.cost()); } }
——代碼來源:學(xué)習(xí)巍扛、探究Java設(shè)計模式——裝飾者模式