深究设计模式之-装饰器模式
装饰器模式(Decorator Pattern) 是一种结构型设计模式,它允许行为在运行时被附加到一个对象上,而不影响其他对象的行为。装饰器模式是通过创建一个包装对象来实现的,该包装对象包含了原始对象,并且可以在执行原始对象的操作之前或之后执行额外的操作。
举个例子,比如我们有一杯普通的咖啡,我们想要让它变得更加特别一些,我们可以先在外面包一层巧克力,然后再在上面撒些彩色砂糖,再放上一片鲜奶油。这些包装就像是装饰器,它们不会改变咖啡本身的味道,但会让它看起来更漂亮、更有吸引力。
在编程中,装饰器模式也是类似的,我们可以在不改变原始对象的情况下,通过添加一些额外的功能来装饰它。这些额外的功能可以是在原有功能之前或之后执行一些操作,或者是给原有功能添加一些新的特性,但最终对象的核心功能仍然是一样的。
主要角色:
- 组件(Component): 定义了被装饰对象和装饰器共同实现的接口。
- 具体组件(Concrete Component): 实现了组件接口的具体对象,是被装饰的对象。
- 装饰器(Decorator): 继承自组件接口,并持有一个组件对象的引用,通过该引用可以调用被装饰对象的方法,并可以在调用前后执行额外的操作。
- 具体装饰器(Concrete Decorator): 扩展了装饰器,实现了额外的操作。
示例:
用java代码实现一下上面这个咖啡店的例子,咖啡是组件,可以被装饰的调料如牛奶和糖是具体装饰器。
package com.luke.designpatterns.decoratorPattern;
// 组件接口
interface Coffee {
double cost();
}
// 具体组件 - 咖啡
class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 5.0;
}
}
// 装饰器
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
@Override
public double cost() {
return decoratedCoffee.cost();
}
}
// 具体装饰器 - 牛奶
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public double cost() {
return super.cost() + 2.0;
}
}
// 具体装饰器 - 糖
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public double cost() {
return super.cost() + 1.0;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建简单咖啡
Coffee coffee = new SimpleCoffee();
System.out.println("简单咖啡:" + coffee.cost() + "元");
// 使用装饰器加牛奶
Coffee milkCoffee = new MilkDecorator(coffee);
System.out.println("加牛奶的咖啡:" + milkCoffee.cost() + "元");
// 使用装饰器加牛奶和糖
Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
System.out.println("加牛奶和糖的咖啡:" + sugarMilkCoffee.cost() + "元");
}
}
在这个例子中,Coffee
是组件接口,SimpleCoffee
是具体组件,CoffeeDecorator
是装饰器。MilkDecorator
和 SugarDecorator
是具体装饰器,它们通过继承和组合的方式实现对咖啡的装饰。客户端可以选择使用不同的装饰器组合来获取不同口味的咖啡,而不需要改变原始的咖啡对象。这符合开闭原则,即对扩展开放,对修改关闭。
适用场景
装饰器模式适用于以下场景:
- 动态地给对象添加额外的功能:当需要在不修改原始对象的情况下,动态地添加功能或行为时,装饰器模式非常有用。例如,在运行时根据需求添加日志记录、权限检查等功能。
- 避免创建子类的过多:当需要为类的功能添加多个不同的组合时,使用继承可能导致类爆炸,而装饰器模式允许通过组合的方式动态地添加功能,避免创建过多的子类。
- 保持类的简单性:装饰器模式可以保持原始类的简单性,因为它们只需要关注核心功能,而将装饰逻辑分离出来,这样使得类的设计更加清晰。
- 动态地移除功能:与添加功能相反,装饰器模式也可以用于动态地移除对象的功能。这在某些情况下可能是有用的,例如根据条件选择性地移除某些功能。
- 需要透明地扩展对象的功能:装饰器模式允许透明地扩展对象的功能,即客户端代码不需要知道对象是否被装饰,仍然可以使用原始对象的接口。
总的来说,装饰器模式适用于需要动态地添加或移除对象功能,同时保持对象简单性和透明性的情况。
转载自:https://juejin.cn/post/7351700046485913609