专注IT技术、资源分享!
【设计模式系列】我用装饰器模式造了一台豪华跑车
【设计模式系列】我用装饰器模式造了一台豪华跑车

【设计模式系列】我用装饰器模式造了一台豪华跑车

前言

一般情况下如果我们想要对一个对象进行扩展,会使用继承或组合的方式来进行,这个扩展的动作发生在编译时,比如在继承扩展时,子类的所有对象在编译时就已经确定有什么特性。

而如果需要在运行时按照不同的情况进行不同的功能扩展,并且不会对现有对象的功能进行添加和删除,则需要用装饰器模式来实现。

装饰器模式定义

装饰器模式(Decorator Design Pattern)用于在运行时修改对象的功能。同时,同一类的其他实例将不受此影响,因此单个对象将获得修改后的行为。装饰器设计模式是结构设计模式(如适配器模式、桥接模式、组合模式)的一种,它使用抽象类或具有组合的接口来实现。

假设我们想要实现不同类型的汽车,我们可以创建接口Car来定义汽车有哪些功能(接口中的方法),然后我们可以有一个基本款汽车实现类,进一步我们可以将基本款扩展到跑车和豪华车。实现层次结构如下图所示。

但是,如果我们想在运行时得到一辆同时具有跑车和豪华车特性的汽车,那么实现就会变得复杂,如果我们想进一步指定应该首先添加哪个特性,它就会变得更加复杂。现在想象一下,如果我们有10种不同的汽车,那么使用继承和组合的实现逻辑将会变得特别难以管理。为了解决这种编程问题,我们在java中应用了装饰器模式。

实现装饰器模式一般需要以下类型的组件。

组件接口

定义要实现的方法的接口或抽象类。在我们的例子中,Car将是组件接口。

public interface Car {

public void assemble();
}

组件实现

组件接口的基本实现。我们可以将BasicCar类作为组件实现。

public class BasicCar implements Car {
@Override
public void assemble() {
System.out.print("基本款汽车.");
}
}

装饰器

Decorator类实现了组件接口,并且它与组件接口具有has-a关系。组件变量应该可以被子装饰器类访问,因此我们将这个变量设置为protected

public class CarDecorator implements Car {

   protected Car car;

   public CarDecorator(Car c){
       this.car=c;
  }
   
   @Override
   public void assemble() {
       this.car.assemble();
  }

}

扩展基本装饰器功能并相应地修改组件行为。我们可以有具体的装饰器类,如LuxuryCarSportsCar

跑车装饰器实现:

public class SportsCar extends CarDecorator {

   public SportsCar(Car c) {
       super(c);
  }

   @Override
   public void assemble(){
       super.assemble();
       System.out.print("添加跑车特性");
  }
}

豪华车装饰器实现:

public class LuxuryCar extends CarDecorator {

public LuxuryCar(Car c) {
super(c);
}

@Override
public void assemble(){
super.assemble();
System.out.print("添加豪华车特性");
}
}

测试类:

public class DecoratorPatternTest {

public static void main(String[] args) {
Car sportsCar = new SportsCar(new BasicCar());
sportsCar.assemble();
// 可以灵活地对目标对象BasicCar进行扩展(装饰)
Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
sportsLuxuryCar.assemble();
}

}

在测试代码中,我们可以对目标对象BasicCar灵活扩展,并且SportCar和LuxuryCar的顺序可以改变。

装饰器模式类图

小结

装饰器设计模式有助于提供运行时修改功能,因此更加灵活。当选择数量较多时,易于维护和扩展。

装饰器模式在Java IO类中使用较多,如FileReader、BufferedReader等。

发表回复

您的电子邮箱地址不会被公开。