Java 23种设计模式系列之装饰者模式(常用)

目录

一、装饰者模式(Decorator)的概念

什么是装饰者模式?

使用场景:

装饰者包含的角色:

 结构图:

优点:

缺点:

二、装饰者模式示例演示

咖啡馆订单系统项目

设计方案:

代码:


一、装饰者模式(Decorator)的概念

什么是装饰者模式?

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式比生成子类更为灵活。

装饰者模式是一种对象结构型模式。

使用场景:

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:①第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;②第二类是因为类定义不能继承(如final类).

装饰者包含的角色:

抽象构件角色(Component):定义一个对象接口或抽象类,可以给这些对象动态地添加职责,也称为主体。

具体构件角色(ConcreteComponent):实际被动态地添加职责的对象。

抽象装饰者角色(Decorator):实现了Component接口,用来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。

具体装饰者角色(ConcreteDecorator):动态地添加职责的对象。

 结构图:

优点:

1、装饰者模式和继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活型。

2、通过使用不同的具体装饰者类及它们不同的组合顺序,可以得到不同装饰后具有不同行为或者状态的对象。例如上面的CarDecoratorImpl可以多次修饰一个男人,证明他有很多车。

3、符合开闭原则。

缺点:

1、增加了抽象装饰者类和具体装饰者类,一定程度增加了系统的复杂度,加大了系统的学习和理解成本。

2、灵活性也意味着更容易出错,对于多次被多次修饰的对象,调试时寻找错误可能需要找到多个地方。

二、装饰者模式示例演示

咖啡馆订单系统项目

咖啡馆订单项目:

1)、咖啡种类:Espresso、ShortBlack(浓缩)、LongBlack、Decaf (无糖)(这些就是相当咖啡的基础,单品咖啡,基础元素,所有的咖啡都是在此基础上混合起来了的)

2)、调料:Milk、Soy、Chocolate  (往基础品种中加入牛奶,巧克力等等,就组成了类似巧克力味咖啡,摩卡,卡夫奇诺等等。我们一般在咖啡厅一般都是直接点卡夫奇诺,其价格就是有单品咖啡和各种调料相加在一起的价格。)

3)、咖啡馆订单项目设计原则(或者是需求):扩展性好、改动方便、维护方便

设计方案:

 这里主体跟实体大致不变,主要在抽象主体与调料中间添加了一个中间层。中间层的作用就是在调用cost的时候,他是要进行费用的叠加的,还有一个重要的就是中间层引入了一个Drink对象,这个对象其实包含着被装饰的对象,这个被装饰的对象,在调用coat的时候我们会获取他的费用,然后通过递归的放方式去获取这一级所有费用、同时具体装饰的名字可以通过getDescription()获取。就是外面包装那么多东西,也可以获取出来。

代码:

抽象超类

package com.java.jikexueyuan.coffeebar;
/*
 * 
 * 首先定一个Drink超类,抽象类 ;在抽象类的基础上扩展出两个分支,一个是咖啡的单品
 * ,这里咖啡可以设置个中间层,这里实现了中间层,Coffee中间层,这个中间层把单品的公有功能放进去了;一个是调料,
 * 装饰者分支Decorator,这个装饰者本身就是个中间层,在这Decorator里面实现共有功能,具体的调料去继承这个中间层去实现即可
 * 这样,代码接口就比较清晰了
 */
public abstract class Drink {
	public String description=""; //这个描述具体扩展出是什么单品或调料
	private float price=0f;; //这里是具体的单品或调料的价格
	
	
	public void setDescription(String description)
	{
		this.description=description;
	}
	
	public String getDescription()
	{
		return description+"-"+this.getPrice();
	}
	public float getPrice()
	{
		return price;
	}
	public void setPrice(float price)
	{
		this.price=price;
	}
	public abstract float cost();  //这个是用抽象是因为,在单品种直接返回价格即可,
	//但在调料中,调料是不能单独存在的,是跟着实体,具体实体一起的,价格不仅是调料还有单品的价格,调料cost方法是是要递归去获取所有调料的价格
}
package com.java.jikexueyuan.coffeebar.coffee;
 
import com.java.jikexueyuan.coffeebar.Drink;
//这是个具体主题分支上面的中间层
public  class Coffee extends Drink {
 
	@Override
	public float cost() { //在实现是直接返回价格即可,因为单品就单品一个,实现简单
		// TODO Auto-generated method stub
		return super.getPrice();
	}
 
	
}

package com.java.jikexueyuan.coffeebar.coffee;
 
public class Decaf extends Coffee {
	public Decaf()
	{
		super.setDescription("Decaf");
		super.setPrice(3.0f);
	}
}

package com.java.jikexueyuan.coffeebar.decorator;
 
import com.java.jikexueyuan.coffeebar.Drink;
//装饰者分支 中间层
public  class Decorator extends Drink {
	private Drink Obj;//注意这里面有个超类的对象,因为这是个装饰者,
	//所以他包装的是一个单品,或者是一个被包装过的单品.所以他用个超类的类型
 
	public Decorator(Drink Obj){//所以实现这个装饰者时必须带入这个Drink对象放进去
		this.Obj=Obj;
	};
	
	//这里的价格计算就有所跟单品不一样了。首先他要计算自己的价格,比如,巧克力,牛奶多少钱,还有要计算的就是前面
	//带入的主题的价格,如果是已包装过的,就变成了递归了,就迭代的计算所有价格,以级最终的单品价格
	@Override
	public float cost() {
		// TODO Auto-generated method stub
		
		return super.getPrice()+Obj.cost();
	}
 
	@Override
	public String getDescription()
	{
		return super.description+"-"+super.getPrice()+"&&"+Obj.getDescription();
	}
	
	}
package com.java.jikexueyuan.coffeebar.decorator;
 
import com.java.jikexueyuan.coffeebar.Drink;
 
public class Chocolate extends Decorator {
 
	public Chocolate(Drink Obj) {		
		super(Obj);
		// TODO Auto-generated constructor stub
		super.setDescription("Chocolate");
		super.setPrice(3.0f);
	}
 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值