您的位置:首页 > 编程语言 > Java开发

java设计模式--装饰者模式

2015-05-15 14:56 465 查看

装饰者模式

假设给我个题目,现在Coffe bar 有四种beverage,such as HouseBlend(0.89$$),Dark Roast(0.99$), Espreso(1.99$), Decaf(1.05$),供我选择,每种beverage,你可以选择加Milk(0.1$),Mocha(0.2$),Soy(0.15$),Whip(0.2$),要我来设计一个程序来实现。

于是我就码出了如下程序:

package Decorator;

public abstract class Beverage {
String description = "Unknown Beverage";
private boolean milk=false;
private boolean mocha=false;
private boolean soy=false;
private boolean whip=false;

public boolean hasMilk(){
return milk;
}

public void setMilk(boolean milk){
this.milk = milk;
}

public boolean hasMocha(){
return mocha;
}

public void setMocha(boolean mocha){
this.mocha = mocha;
}

public boolean hasSoy(){
return soy;
}

public void setSoy(boolean Soy){
this.soy = Soy;
}

public boolean hasWhip(){
return whip;
}

public void setWhip(boolean Whip){
this.whip = Whip;
}

public String getDescription() {
return description;
}

public double cost(){
double condimentCost = 0.0;
if(hasMilk()){
condimentCost+=0.1;
}
if(hasMocha()){
condimentCost+=0.2;
}
if(hasSoy()){
condimentCost+=0.15;
}
if(hasWhip()){
condimentCost+=0.1;
}
return condimentCost;
}
}


package Decorator;
public class DarkRoast extends Beverage {
public DarkRoast(){
description = "Most Excellent Dark Roast";
}

public double cost(){
return 0.99+super.cost();
}
}

package Decorator;
public class Decaf extends Beverage{
public Decaf(){
description = "Most Excellent Decaf";
}

public double cost(){
return 1.05+super.cost();
}
}

package Decorator;
public class Espresso extends Beverage{
public Espresso(){
description = "Most Excellent Espresso";
}

public double cost(){
return 0.99+super.cost();
}
}

package Decorator;
public class HouseBlend extends Beverage{
public HouseBlend(){
description = "Most Excellent House Blend";
}

public double cost(){
return 0.89+super.cost();
}
}


package Decorator;
public class Client {
public static void main(String[] args) {
Beverage bg = new HouseBlend();
bg.setMilk(true);//add milk
bg.setMocha(true);//add mocha
System.out.println(bg.getDescription());
System.out.println(bg.cost());
}
}/*
Most Excellent House Blend
1.19
*/


piece of cake!!

不过转念一想,如果我想再加上一种原料,是不是就有点麻烦了!比如honey(0.1$),这时我就要手动修改beverage这个类了,貌似麻烦了一点;

package Decorator;

public abstract class Beverage {
String description = "Unknown Beverage";
private boolean milk=false;
private boolean mocha=false;
private boolean soy=false;
private boolean whip=false;
private boolean honey=false;
public boolean hasMilk(){
return milk;
}
public void setMilk(boolean milk){
this.milk = milk;
}
public boolean hasMocha(){
return mocha;
}
public void setMocha(boolean mocha){
this.mocha = mocha;
}
public boolean hasSoy(){
return soy;
}
public void setSoy(boolean Soy){
this.soy = Soy;
}
public boolean hasWhip(){
return whip;
}
public void setWhip(boolean Whip){
this.whip = Whip;
}
public boolean hasHoney(){
return honey;
}
public void setHoney(boolean honey){
this.honey= honey;
}
public String getDescription() {
return description;
}

public double cost(){
double condimentCost = 0.0;
if(hasMilk()){
condimentCost+=0.1;
}
if(hasMocha()){
condimentCost+=0.2;
}
if(hasSoy()){
condimentCost+=0.15;
}
if(hasWhip()){
condimentCost+=0.1;
}
if(hasHoney()){
condimentCost+=0.1;
}
return condimentCost;
}
}


如果我有上百种原料,想一想,beverage这个类肯定会更复杂,且不符合抽象的原则。那应该怎么办呢?

想到这里我们第一反应就是这些原料最好继承某个基类,这样可以方便添加;那原料和beverage怎么关联呢? 就产生了下图那个装饰者模式的基本形式,beverage类可以灵活的添加原料



所有的ConcreteDecorator类似 于这里的原料均继承于Decorator这个抽象类,这个抽象类又继承于beverage这个基类。

如下图:



package headfirst.decorator.starbuzz;

public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}


package headfirst.decorator.starbuzz;

public class DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}
public double cost() {
return .99;
}
}


package headfirst.decorator.starbuzz;

public class Decaf extends Beverage {
public Decaf() {
description = "Decaf Coffee";
}
public double cost() {
return 1.05;
}
}


package headfirst.decorator.starbuzz;

public class Espresso extends Beverage {

public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}


package headfirst.decorator.starbuzz;

public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}
public double cost() {
return .89;
}
}


package headfirst.decorator.starbuzz;

public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}


package headfirst.decorator.starbuzz;

public class Milk extends CondimentDecorator {
Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
public double cost() {
return .10 + beverage.cost();
}
}


package headfirst.decorator.starbuzz;

public class Mocha extends CondimentDecorator {
Beverage beverage;

public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost();
}
}


package headfirst.decorator.starbuzz;

public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
public double cost() {
return .15 + beverage.cost();
}
}


package headfirst.decorator.starbuzz;

public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}


package headfirst.decorator.starbuzz;

public class StarbuzzCoffee {
public static void main(String args[]) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());

Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()
+ " $" + beverage2.cost());

Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription()
+ " $" + beverage3.cost());
}
}/*Output
Espresso $1.99
Dark Roast Coffee, Mocha, Mocha, Whip $1.49
House Blend Coffee, Soy, Mocha, Whip $1.34
*/


这时我想扩充原料的类型时,我只有再继承一个原料类就可以了,比如Honey(0.1$)

package headfirst.decorator.starbuzz;

public class Honey extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Honey";
}
public double cost() {
return .10 + beverage.cost();
}
}


装饰者模式在Java I/O实例中的应用:



package headfirst.decorator.io;
import java.io.*;

public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toLowerCase((char)c));
}
public int read(byte[] b, int offset, int len) throws IOException {
int result = super.read(b, offset, len);
for (int i = offset; i < offset+result; i++) {
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}


package headfirst.decorator.io;
import java.io.*;

public class InputTest {
public static void main(String[] args) throws IOException {
int c;
try {
InputStream in =
new LowerCaseInputStream(
new BufferedInputStream(
new FileInputStream("test.txt")));
while((c = in.read()) >= 0) {
System.out.print((char)c);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


参考文献

Head First Design Pattern

大话设计模式

Thinking in Java
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: