引入
在看数据库连接池这一章内容的时候,出现了面向接口编程和装饰者模式的设计模式。利用装饰者设计模式把数据库连接池接口的实现类(被装饰者)的close方法重写(重写其实也算是一种“添加”)了。
可能从上文很难看得出这是一个什么样的问题,那么下文便用咖啡的例子帮助大家理解到底装饰者模式解决了什么问题:
假设有四种咖啡:HouseBlend、DarkRoaat、Decaf、Espresso。
同样有四种可以搭配的选择:Milk、Mocha、Soy、Whip。这四种咖啡有不同的价格、同样四种搭配也有不同的价格。当我们把这个单子拿给顾客的时候、顾客可以任意点一种咖啡、可以任意搭配。我们的目的是要统计每种搭配的价格、那我们要写多少个类?最后的结果就是类爆炸!
当我们要添加一个新的品种的时候、如果按照上面的方法、那我们就要新添加N多类来实现目的。如何有效的解决这两个问题?也许你有别的很多方法与思想、这里只是说明装饰者模式的使用。
——来源于:Java设计模式之装饰者模式
再举一个例子,也是后面写程序阐述的:
假设现在有一个进服装店的人
服装店里有帽子、T恤、裙子
那么用程序来描述:
用Person类描述这个人
如果用继承方法,
当这个人戴上帽子的时候需要一个描述戴帽子的人的子类:HatPerson(继承Person)
当这个人穿上T恤的时候需要一个描述穿T恤的人的子类:TshirtPerson(继承Person)
当这个人穿上裙子的时候需要一个描述穿裙子的人的子类:SkirtPerson(继承Person)
既戴帽子又穿T恤的时候需要一个描述的子类:HatTshirtPerson(继承Person或同时继承HatPerson与TshirtPerson)
......
可以看到,如果用这样来描述问题,非常复杂。因为本身“继承”描述的关系就是一类事物的细分,而不是类似这样的对事物进行某一部分的添油或加醋问题。而很明显,利用“装饰”这一设计概念,可以更灵活的描述这类问题。
什么是装饰者模式?
为了更好描述,需要对某个类(一个类可以看成描述的一个事物:例如一个人)的某个部分(类中的一个成员,例如一个人身上穿的衣服)进行修改或重写的这种问题的模式。
啥时候用?有啥样的效果?
由上可以总结出(附上代码示例):
- 当需要对某个类进行部分成员变量或方法的时候使用
A Sample
为了更加深刻地理解装饰者模式,我们来看一个简单的栗子。首先,我们假设现在 有这样一个需求:你有一家服装店,卖各式各样的衣服,现在需要用一个系统来记录客户所要购买的衣服的总价,以便方便地结算。那么在这个例子里面,我们可以用装饰者模式,把客户当做被装饰者,衣服是装饰者,这很直观形象吧,接着我们来一步步实现需求。Step 1、创建Component基类
因为总体对象是人,所以我们可以把人抽象为基类,新建Person.java:
public abstract class Person {
String description = "Unkonwn";
public String getDescription()
{
return description;
}
public abstract double cost(); //子类应该实现的方法
}
Step 2、创建被装饰者——ConcreteComponent
客户分为很多种,有儿童、青少年、成年人等,因此我们可以创建不同的被装饰者,这里我们创建青少年的被装饰者,新建Teenager.java:
public class Teenager extends Person {
public Teenager() {
description = "Shopping List:";
}
@Override
public double cost() {
//什么都没买,不用钱
return 0;
}
}
Step 3、创建Decorator
由于不同的部位有不同的衣物,不能混为一谈,比如说,衣服、帽子、鞋子等,那么这里我们创建的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、创建ConcreteDecorator
上面既然已经创建了两种Decorator,那么我们基于它们进行拓展,创建出不同的装饰者,对于Clothing,我们新建Shirt.java,对于Hat,我们新建Casquette,其实可以根据不同类型的衣物创建更多不同的装饰者,这里只是作为演示而创建了两种。代码如下所示:
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(); //实现了cost()方法,并调用了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();
}
}
- 效果:能够对基类(Person)的实例不断的修改其成员
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()); } }
——代码来源:学习、探究Java设计模式——装饰者模式
网友评论