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

749 阅读3分钟

这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

前言

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

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

装饰器模式定义

装饰器模式(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等。

如果对你有帮助,点个赞是对我最大的鼓励。