版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Smy_0114/article/details/80653127
参考https://blog.csdn.net/wwh578867817/article/details/51480441
下面有一般模式和装饰器模式对比。
一:先一般模式需要什么对象直接新建一个类,比如:咖啡,牛奶咖啡,加糖咖啡,糖牛奶咖啡等等越多越复杂。
1.饮料接口
package 一般模式;
/**
* 饮料接口:可以是任何饮料,比如咖啡,茶,红牛······
*
* @author smy
*
*/
public interface Drink {
/**
* 饮料的价格。
* @return
*/
public float cost();
/**
* 饮料的描述,也就是饮料的名称,比如红牛,咖啡,茶······
* @return
*/
public String getDescription();
}
2.咖啡
package 一般模式;
/**
* 咖啡饮料,实现了饮料接口。
* @author smy
*
*/
public class Coffee implements Drink {
@Override
public float cost() {
// TODO 每杯售价10元人民币。
return 10;
}
@Override
public String getDescription() {
// TODO 原味咖啡。
return "咖啡";
}
}
3.牛奶咖啡
package 一般模式;
public class MilkCoffee implements Drink{
@Override
public float cost() {
// TODO Auto-generated method stub
return 12;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return "牛奶咖啡";
}
}
4.糖咖啡
package 一般模式;
public class SugarCoffee implements Drink{
@Override
public float cost() {
// TODO Auto-generated method stub
return 11;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return "加糖咖啡";
}
}
5.牛奶糖咖啡
package 一般模式;
public class MilkSugarCoffee implements Drink{
@Override
public float cost() {
// TODO Auto-generated method stub
return 14;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return "牛奶加糖咖啡";
}
}
6.测试
package 一般模式;
public class App {
public static void main(String[] args) {
Drink drink = new MilkSugarCoffee();
System.out.print(drink.cost());
System.out.println(drink.getDescription());
drink = new SugarCoffee();
System.out.print(drink.cost());
System.out.println(drink.getDescription());
}
}
7.总结:一般模式这种实现也可以用,简单的业务可以,但涉及到复杂的就显得有点力不从心了。
二:装饰器模式,其实就是比一般模式多了个装饰类,具体的实现类需要继承此装饰类而已。
先来一张结构图
1.饮料接口不变
package 装饰器模式;
/**
* 饮料接口:可以是任何饮料,比如咖啡,茶,红牛······
*
* @author smy
*
*/
public interface Drink {
/**
* 饮料的价格。
* @return
*/
public float cost();
/**
* 饮料的描述,也就是饮料的名称,比如红牛,咖啡,茶······
* @return
*/
public String getDescription();
}
2.咖啡不变
package 装饰器模式;
/**
* 咖啡饮料,实现了饮料接口。
* @author smy
*
*/
public class Coffee implements Drink {
@Override
public float cost() {
// TODO 每杯售价10元人民币。
return 10;
}
@Override
public String getDescription() {
// TODO 原味咖啡。
return "咖啡";
}
}
3.装饰器
package 装饰器模式;
/**
* 条件装饰器饮料,也是饮料当作是超级饮料,用来继承的。
* @author smy
*
*/
public abstract class CondimentDecorator implements Drink{
protected Drink decoratorDrink;
public CondimentDecorator (Drink decoratorDrink){
this.decoratorDrink=decoratorDrink;
}
public CondimentDecorator ( ){
}
@Override
public float cost() {
// TODO Auto-generated method stub
return decoratorDrink.cost();
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return decoratorDrink.getDescription();
}
}
4.牛奶
package 装饰器模式;
public class Milk extends CondimentDecorator{
public Milk(Drink decoratorDrink) {
super(decoratorDrink);
// TODO Auto-generated constructor stub
}
@Override
public float cost() {
// TODO Auto-generated method stub
return super.cost()+2;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return super.getDescription()+"牛奶味";
}
}
5.糖
package 装饰器模式;
public class Sugar extends CondimentDecorator{
public Sugar(Drink decoratorDrink) {
super(decoratorDrink);
// TODO Auto-generated constructor stub
}
@Override
public float cost() {
// TODO Auto-generated method stub
return super.cost()+1;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return super.getDescription()+"加糖";
}
}
6.冰块
package 装饰器模式;
public class Ice extends CondimentDecorator{
public Ice(Drink decoratorDrink) {
super(decoratorDrink);
// TODO Auto-generated constructor stub
}
@Override
public float cost() {
// TODO Auto-generated method stub
return super.cost()+5;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return super.getDescription()+"冰块";
}
}
8.测试
package 装饰器模式;
/**
* 假设我们现在去咖啡店要了一杯咖啡,可以加奶、加糖等等。咖啡和奶、糖分别有不同的价格。
* 咖啡就是我们的组件,奶和糖是我们的装饰者,现在我们要计算调制这样一杯咖啡花费多少。
* -----------------------------------------------------------------------------
* @author smy
*
*/
public class App {
public static void main(String[] args) {
Drink drink = new Coffee();
System.out.print(drink.cost());
System.out.println(drink.getDescription());
drink=new Milk(drink);
System.out.print(drink.cost());
System.out.println(drink.getDescription());
drink =new Sugar(drink);
System.out.print(drink.cost());
System.out.println(drink.getDescription());
drink =new Ice(drink);
System.out.print(drink.cost());
System.out.println(drink.getDescription());
}
}
9.总结:刚开始接触感觉装饰器模式更复杂,但是在熟悉之后装饰器模式是很不错的选择。
10.为什么要用装饰器模式:
装饰者模式(Decorator Pattern),是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。(包裹真是的对象,也就是装饰器类里面有原始对象)
使用装饰者模式的时候需要注意一下几点内容:
(1)装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。(什么意思呢,就是说new一个装饰器对象可以指向公共的接口)
(2)装饰对象包含一个真实对象的引用。
(3)装饰对象接受所有的来自客户端的请求,它把这些请求转发给真实的对象。
(4)装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。然而,装饰者模式,不需要子类可以在应用程序运行时,动态扩展功能,更加方便、灵活(意思就是不用改变coffee对象,只增加装饰的条件即可也就是糖,牛奶之类的对象,这跟普通模式增加子对象不同,此处增加的装饰条件可复用。)。
适用装饰者模式场合:
1.当我们需要为某个现有的对象,动态的增加一个新的功能或职责时,可以考虑使用装饰模式。
2.当某个对象的职责经常发生变化或者经常需要动态的增加职责,避免为了适应这样的变化,而增加继承子类扩展的方式,因为这种方式会造成子类膨胀的速度过快,难以控制。