装饰模式,顾名思义,就是美化、强化原有事物的意思。
增强功能,我们知道java的继承就可以实现,那要装饰模式干嘛?
区别就在”动态”,装饰模式可以动态的给对象增强,并且避免类爆炸。
试想,如果为实现一个特定功能,就要实现一个子类,那如果要实现很多功能,岂不是要很多子类,且一旦子类确定,其功能在编译时期就是确定的,是静态的。
在java中,IO就充分使用了该模式。我们看到了在java IO 中,有Reader、Writer、InputStream、OutputStream等抽象类,其他的类无非就是对这些类的装饰、增强。
装饰者与被装饰者拥有共同的超类。
举个例子:
我们想在网上买个手机,假如买的是苹果X,4000大洋,然后呢!只有裸机,我们又想买点配件来增强它的功能,网店上有很多配件,如:手机壳30大洋,Beats耳机500大洋等等。
我们现在用继承来处理这个问题,
定义一个手机抽象类,一个苹果手机类
手机抽象类:(Mobile.java)
package extend;
/**
* 手机抽象类
*/
public abstract class Mobile {
/**
* 手机名称
*/
protected String name;
/**
* 价格
*/
protected Double price;
/**
* 获取名称
* @return
*/
public abstract String getName();
/**
* 获取售价
* @return
*/
public abstract double getPrice();
}
苹果手机类(AppleMobile.java)
package extend;
/**
* 苹果手机
*/
public class AppleMobile extends Mobile{
@Override
public double getPrice() {
return this.price;
}
@Override
public String getName() {
return this.name;
}
public AppleMobile() {
this.name = "苹果手机";
this.price = 5000d;
}
}
如果我们想多买个手机壳,就得实现一个子类
package extend;
/**
* 手机壳+苹果手机 子类
*/
public class MobileCaseAppleMobile extends AppleMobile{
private String mobileCaseName(){
return " + 手机壳";
}
private Double mobileCasePrice(){
return 30d;
}
@Override
public String getName() {
return super.getName() + mobileCaseName();
}
@Override
public double getPrice() {
return super.getPrice() + mobileCasePrice();
}
}
package extend;
public class Demo {
public static void main(String[] args) {
Mobile mobile = new MobileCaseAppleMobile();
System.out.println(mobile.getName());
System.out.println(mobile.getPrice());
}
}
对应输出:
苹果手机 + 手机壳
5030.0
如果我们要买苹果手机+耳机呢?那就又要实现另外一个子类,就相当于一个个套餐(经常看到网店上有那种配套的套餐)。但是,当配件越来越多时,我们就要对应非常非常多的套餐,这中情况下,就会出现所谓的类爆炸。
如果使用装饰模式来处理呢?
我们定义一个手机抽象类,一个苹果手机类,一个配件装饰抽象类,一个耳机配件装饰类,一个手机壳配件装饰类。
手机抽象类:(Mobile.java)
package decorator;
/**
* 手机抽象类
*/
public abstract class Mobile {
/**
* 手机名称
*/
protected String name;
/**
* 价格
*/
protected Double price;
/**
* 获取名称
* @return
*/
public abstract String getName();
/**
* 获取售价
* @return
*/
public abstract double getPrice();
}
苹果手机类(AppleMobile.java)
package decorator;
/**
* 苹果手机
*/
public class AppleMobile extends Mobile{
@Override
public double getPrice() {
return this.price;
}
@Override
public String getName() {
return this.name;
}
public AppleMobile() {
this.name = "苹果手机";
this.price = 5000d;
}
}
配件装饰抽象类(Accessories.java)
package decorator;
/**
* 配件抽象类,这里继承并不是为了继承行为,而是类型
*/
public abstract class Accessories extends Mobile{
/**
* 配件修饰的手机
*/
protected Mobile mobile;
public Accessories(Mobile mobile) {
this.mobile = mobile;
}
//获取配件名称
public abstract String getDecoratorName();
}
耳机配件装饰类(Headset.java)
package decorator;
/**
* 耳机配件装饰类
*/
public class Headset extends Accessories{
public Headset(Mobile mobile) {
super(mobile);
}
@Override
public String getName() {
return mobile.getName() + "+" +getDecoratorName();
}
@Override
public double getPrice() {
return mobile.getPrice() + 500d;
}
@Override
public String getDecoratorName() {
return "Beats耳机";
}
}
手机壳配件装饰类(MobileCase.java)
package decorator;
/**
* 手机壳配件装饰类
*/
public class MobileCase extends Accessories{
public MobileCase(Mobile mobile) {
super(mobile);
}
@Override
public String getName() {
return mobile.getName() + "+" + getDecoratorName();
}
@Override
public double getPrice() {
return mobile.getPrice() + 30d;
}
@Override
public String getDecoratorName() {
return "手机壳";
}
}
package decorator;
public class Demo {
public static void main(String[] args) {
Mobile mobile = new AppleMobile();
System.out.println(mobile.getName());
System.out.println(mobile.getPrice());
mobile = new MobileCase(mobile);
System.out.println(mobile.getName());
System.out.println(mobile.getPrice());
mobile = new Headset(mobile);
System.out.println(mobile.getName());
System.out.println(mobile.getPrice());
}
}
对应输出:
苹果手机
5000.0
苹果手机+手机壳
5030.0
苹果手机+手机壳+Beats耳机
5530.0
如上,我们可以动态组合,动态增强我们需要的手机,如果我们只要苹果手机+手机壳
package decorator;
public class Demo {
public static void main(String[] args) {
Mobile mobile = new AppleMobile();
mobile = new MobileCase(mobile);
System.out.println(mobile.getName());
System.out.println(mobile.getPrice());
}
}
对应输出:
苹果手机+手机壳
5030.0
可以看出,我们使用装饰模式,当要新增加一个配件类型,我们就增加一个配件类。然后,在购买的时候,自由组合就行。