设计模式 - 装饰模式(Decorator)

Decorator/Wrapper 模式动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。
装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。
以下情况使用Decorator模式
• 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
• 处理那些可以撤消的职责。
• 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

类图
这里写图片描述

案例 1: Java IO 类 FilterInputStream是Decorator模式实现
这里写图片描述

案例 2: Collections集合框架中通过Decorator模式实现静态的同步的或不可修改的集合包装器类,然后通过工厂方法返回同步的或不可修改的包装器对象集合。
例如:
Collections.SynchronizedList //static nested class
Collections.unmodifiableList(…)

案例 3:
假设公司里的员工(Employee)分类为工程师(Engineer), 销售人员(Salesman), 和经理(Manager), 他们的薪资计算方式不同,

public class Engineer implements Employee {
    ...
    public int payAmount() {
        return monthlySalary;
    }
}
public class Salesman implements Employee {
    ...
    public int payAmount() {
        return monthlySalary + commission;
    }
}
public class Manager implements Employee {
    ...
    public int payAmount() {
        return monthlySalary + bonus;
    }
}

现在有个需求变化,如果员工在实习期,他的应付薪资减半。
方法 1: 给每个子类增加一个布尔型的新成员变量isInternship,标识员工是否是在实习期,如果是在实习期,工资减半,代码大致如下:

public class Manager implements Employee {
    private boolean isInternship = false;
    ...
    public int payAmount() {
        if (isInternship) return (monthlySalary + bonus)/2;
        return monthlySalary + bonus;
    }
}    

这种方式违背了开放闭合原则(OCP), 而且3 个员工子类都需要修改,而且出现代码重复。

方法 2: Decorator 模式处理这种特殊情况, 定义一个Employee类型的包装器 InternshipEmpployeeWrapper, 它持有一个Employee类型的引用。

public class InternshipEmpployeeWrapper implements Employee {
	private Employee employee; //被装饰对象
	public InternshipEmpployeeWrapper(Employee employee) {
		this.employee = employee; //通过构造器赋值
	}
	public int payAmount() {
        return employee.payAmount()/2;
    }
    ...
}    	

Decorator模式不改变原有的类,包装器和被包装者接口相同,不影响客户调用。

总结
如果一个类的核心功能不变,需要加一些装饰(辅助)功能,通常的做法是向这个类中加入新的变量,添加条件语句处理辅助功能,违背开发闭合原则,增加了类的复杂度。

用Decorator模式的优点:

  • 把装饰功能从类中搬离,简化类。
  • 有效地把类的核心职责和装饰功能区分开来。
  • 可以去除几个相关类中重复的装饰逻辑。

使用Decorator模式的缺点:

  • 装饰对象和被装饰对象不是同一类型。
  • 增加了理解、测试、设计的复杂度

使用Decorator模式重构的步骤:

  1. 确定包装类型 - 被装饰类的实现的接口或父类,包括所有被装饰类的公共方法。
  2. 找到被装饰类添加装饰功能的条件语句,用多态替换条件重构,产生被被装饰类的一个或多个子类。
  3. 使用委托取代继承,将子类转换成装饰类,装饰类中定义一个委托类的字段,通过构造函数赋值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值