设计模式入门之装饰器形式Decorator

设计模式入门之装饰器模式Decorator
//装饰模式定义:动态地给一个对象添加一些额外的职责。
//就增加功能来说,装饰模式比生成子类更为灵活
//这也提现了面向对象设计中的一条基本原则,即:尽量使用对象组合,而不是对象继承
设计模式入门之装饰器形式Decorator
//Component:组件对象的接口,可以给这些对象动态添加职责
//ConcreateComponet:具体的组件对象,实现组件对象接口,通常就是被装饰器装饰的对象,也就是可以给这个对象添加职责
//Decorator:所有装饰器的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象,即被装饰的对象
//在Java中比较常见的一种装饰器模式体现如下:
//new DataInputStream(new BufferedInputStream(new FileInputStream("IOtest.txt")));
//FileInputStream完成他自己的功能,然后由装饰器完成需要增加的功能
//实例:设计一个奖金系统,奖金有月奖金,累计奖金和团队奖金,根据不同的人发不同的奖金
//不使用装饰模式的实现中,各个奖金模块的耦合很严重,当有新的奖励方法时改动很多,扩展不方便
//下面是使用了装饰模式的实现方式:
//数据库模拟类,存储人员销售额,模拟,只给了一个月的销售额
public class TempDB {
	private TempDB() {
	}
	public static Map<String, Double> mapMonthSaleMoney = new HashMap<String, Double>();
	static {
		mapMonthSaleMoney.put("张三", 10000.0);
		mapMonthSaleMoney.put("李四", 20000.0);
		mapMonthSaleMoney.put("王五", 30000.0);
	}
}
//所有奖励方法的父类,标准实现使用了抽象类
public abstract class PrizeCalculor {
	public abstract double calcPrize(String user, Date begin, Date end);
}
//需要被装饰的对象类,比如每个人每个月都会有500块的基本奖金
public class NormalPrizeCalc extends PrizeCalculor {
	public double calcPrize(String user, Date begin, Date end) {
		return 500;
	}
}
//下面是装饰器的父类
public abstract class Decorator extends PrizeCalculor{
	protected PrizeCalculor c;//被装饰的对象
	public Decorator(PrizeCalculor c) {
		this.c = c;
	}
	public double calcPrize(String user, Date begin, Date end) {
		//前后可增加功能
		return this.c.calcPrize(user, begin, end);//默认直接转调被装饰对象的方法
	}
}
//月奖金装饰器类
public class MonthPrizeDecorator extends Decorator{
	public MonthPrizeDecorator(PrizeCalculor c) {
		super(c);
	}
	public double calcPrize(String user, Date begin, Date end) {
		double money = super.calcPrize(user, begin, end);//先获得被装饰对象的奖金
		double prize = TempDB.mapMonthSaleMoney.get(user)*0.03;//计算月奖金
		System.out.println(user+"当月业务奖金"+prize);
		return money+prize;//返回被装饰对象的总奖金
	}
}
//累计奖金装饰器类,作用同上
public class SumPrizeDecorator extends Decorator{
	public SumPrizeDecorator(PrizeCalculor c) {
		super(c);
	}
	public double calcPrize(String user, Date begin, Date end) {
		double money = super.calcPrize(user, begin, end);
		double prize = 100000*0.001;//假设所有人的累计销售额都是100000
		System.out.println(user+"累计奖金"+prize);
		return money+prize;
	}
}
//团队奖金装饰器类,只有项目经理才有
public class GroupPrizeDecorator extends Decorator{
	public GroupPrizeDecorator(PrizeCalculor c) {
		super(c);
	}
	public double calcPrize(String user, Date begin, Date end) {
		double money = super.calcPrize(user, begin, end);
		double group = 0.0;
		for(double d : TempDB.mapMonthSaleMoney.values()) {
			group += d;
		}
		double prize = group * 0.01;
		System.out.println(user+"当月团队业务奖金"+prize);
		return money + prize;
	}
}
//客户端测试类
public class Client {
	public static void main(String[] args) {
		PrizeCalculor calc = new NormalPrizeCalc();
		Decorator d1 = new MonthPrizeDecorator(calc);
		Decorator d2 = new SumPrizeDecorator(d1);
		//把被装饰对象进行组合,calc对象经d1装饰,然后d1对象经d2装饰
		double zs = d2.calcPrize("张三", null, null);
		System.out.println(zs);
		double ls = d2.calcPrize("李四", null, null);
		System.out.println(ls);
		Decorator d3 = new GroupPrizeDecorator(d2);
		//项目经理,d2对象再经d3对象装饰
		double ww = d3.calcPrize("王五", null, null);
		System.out.println(ww);
	}
}
//装饰模式的本质:动态组合
//装饰器模式优点:比继承更加灵活,更容复用功能,简化高层定义
//装饰器模式缺点:会产生很多细粒度对象
//注意:各个装饰器之间最好是完全独立的功能,不要有依赖,这样在进行装饰组合的时候,才没有先后顺序的限制,也就是先装饰谁和后装饰谁都是一样的,否则会大大降低装饰漆组合的灵活性

2楼IamMaking6小时前
感觉学以下UML还是有用途的,可以在抽象层面看清整个系统或功能的结构
1楼IamMaking6小时前
看了那么多模式,发现有一些模式比较难以理解,从这个模式开始,先从整体上了解整个模式,如模式结构图,看完入门解释并了解了各个模块的作用后,自己可以根据结构图把整个模式实现出来,看了这么长时间,这才是正确的学习方法,以前学得太慢了,发现以前慢也是好事,证明已经掌握学习方法了,有时间把之前的设计模式都再重新实现一遍,毕竟学习设计模式是为了应用,最标准的结构和实现方法都不能掌握的话还怎么学以致用。而且以后找工作什么的肯定也会用到,让写个设计模式写不出来,怎么好意思说自己看过设计模式呢