一.简介
普通班的学生在上课的时候是听课,而小班的学生在上课的之前会预习,下课之后会复习,他们相当于普通学生的加强版.我们可以选择使用继承来实现他们的关系,但是这并不复合继承的思想,超级班的学生并不是普通班的学生中的一员.
我们选择使用装饰器模式,使用一个新类,在这个类中引入我们需要加强的类(被装饰者),这样我们对它原先的方法进行重写.这样的好处在于我们并不需要维护复杂的继承关系.
二.结构
- 被装饰对象:需要进行加强的类;它的功能不能满足我们现阶段的要求;
- 抽象装饰器:在本类中引入被装饰者对象,一般使用构造方法的方式进行引入;
- 公共抽象的接口:需要在面向接口的前提下才会有公共的抽象接口,如果没有这个接口,装饰器也可以实现,参考StringBuffer和String并没有实现同一个接口.而java中的io的装饰器都实现了同样的接口;
- 具体装饰器:实现和添加具体的功能.
三.代码
版本一 使用类结构,面向类编程
使用最简单的两个类即可完成装饰器的思想,核心思想就是加强我们的原先的类的功能.但是这种方式不是面向接口的编程方式;使用类编程的弊端有很大,没有遵守规范的话,也没有能约束它的接口.
class Student {
public void study() {
System.out.println("上课");
}
}
class SuperStudent {
private Student student;
public SuperStudent(Student student) {
this.student = student;
}
public void study() {
System.out.println("预习");
student.study();
System.out.println("复习");
}
}
public class Client {
public static void main(String[] args) {
SuperStudent superStudent = new SuperStudent(new Student());
superStudent.study();
}
}
版本二 抽象公共接口
此版本使用统一抽象的接口,装饰者和被装饰者都继承了这个接口,客户端的学习成本和调用成本明显降低.
interface Student{
void study();
}
class CommonStudent implements Student{
@Override
public void study() {
System.out.println("上课.....");
}
}
class SuperStudent implements Student{
private Student student;
public SuperStudent(Student student) {
this.student = student;
}
@Override
public void study() {
System.out.println("预习");
student.study();
System.out.println("复习");
}
}
public class Client {
public static void main(String[] args) {
SuperStudent superStudent = new SuperStudent(new CommonStudent());
superStudent.study();
}
}
版本三 提取抽象的装饰器
装饰者进一步进行了抽象,这样具体的装饰器可以选择继承装饰器.对代码又一次进行了优化,但是这种情况不是我们必须选择的,而我们一般最好的选择为版本二,除非我们已经确定了将会有很多的具体装饰器.不然我们没有理由去多写一个类,增加我们代码结构的复杂度.
interface Student{
void study();
}
class CommonStudent implements Student {
@Override
public void study() {
System.out.println("上课.....");
}
}
abstract class DecoratorStudent implements Student{
protected Student student;
public DecoratorStudent(Student student) {
this.student = student;
}
}
// 超级学生
class SuperStudent extends DecoratorStudent {
public SuperStudent(Student student) {
super(student);
}
@Override
public void study() {
System.out.println("预习");
student.study();
System.out.println("复习");
}
}
class BadStudent extends DecoratorStudent{
public BadStudent(Student student) {
super(student);
}
@Override
public void study() {
System.out.println("捣蛋");
student.study();
}
}
public class Client {
public static void main(String[] args) {
SuperStudent superStudent = new SuperStudent(new CommonStudent());
superStudent.study();
System.out.println("==================================================");
BadStudent badStudent = new BadStudent(new CommonStudent());
badStudent.study();
}
}
四.特点
- 不使用继承而是用组合的方式来对一个类进行添加和减少功能;
- 易于扩展:这是在情况三的代码结构下,我们需要新添加一个具体的装饰器只需要继承抽象类即可,当然情况二需要添加装饰器也不是很复杂,只需要实现同样的接口即可;
- 它与代理模式极其的相似,可以说在代码上基本无差异,但是在目的上他们不是一个意思,代理模式的目的是访问控制.所以名曰代理,而装饰器的目的是了加强对象的方法.
- 简单实用:在我们经常使用的jdk中的api中就有大量的此模式,例如StringBuffer,BufferedRead.
五.总结
装饰器模式的使用不会很复杂,如果从目的上来说的话,我们很多时候可能都使用到了它,我们在一个类中引进一个新的类,对它的原先的方法进行调用,并且进行了一些其他的操作,这些操作可以看成加强原先类的动作.
六.参考文献
大话设计模式