结构型模式
- 适配器模式(Adapter Pattern)
- 桥接模式(Bridge Pattern)
- 组合模式(Composite Pattern)
- 装饰器模式(Decorator Pattern)
- 外观模式(Facade Pattern)
- 享元模式(Flyweight Pattern)
- 代理模式(Proxy Pattern)
装饰器模式(Decorator Pattern)是一种结构型设计模式,旨在动态地给一个对象添加额外的功能,而不需要修改其结构。装饰器模式通过使用组合(而非继承)来扩展对象的功能,允许你在运行时对对象进行扩展。
装饰器模式的核心思想:
- 不改变对象的原有功能,而是在原有功能的基础上增加新的功能。
- 通过将装饰功能封装在装饰器类中,使得功能的增加和修改更加灵活。
- 装饰器模式通常与继承相对,继承会通过扩展类来增加功能,而装饰器模式是通过组合不同的装饰器对象来增强功能。
主要角色:
- Component(组件):定义了一个接口,通常是一个抽象类或者接口,规定了被装饰的对象和装饰器的共同接口。
- ConcreteComponent(具体组件):实现了Component接口的基本功能,是被装饰的目标对象。
- Decorator(装饰器):是一个抽象类,持有一个Component对象,并在其功能上进行扩展。它继承了Component接口,并将所有方法委托给实际的Component对象。
- ConcreteDecorator(具体装饰器):继承自Decorator,负责具体的功能扩展(例如添加新功能或修改现有功能)。
装饰器模式的示例:咖啡店
假设我们要设计一个咖啡的销售系统,其中有不同种类的咖啡(例如:单纯的黑咖啡、加了牛奶的咖啡、加了糖的咖啡等),每种咖啡在基础上都有不同的装饰。我们可以使用装饰器模式来动态地为咖啡添加不同的配料。
// 组件接口,所有的咖啡都实现这个接口
public interface Coffee {double cost(); // 计算价格String ingredients(); // 获取配料信息
}// 具体组件,代表普通的黑咖啡
public class BlackCoffee implements Coffee {@Overridepublic double cost() {return 5.0; // 黑咖啡的基础价格}@Overridepublic String ingredients() {return "Black Coffee"; // 黑咖啡的配料}
}// 装饰器,持有一个Coffee对象,并且可以增强其功能
public abstract class CoffeeDecorator implements Coffee {protected Coffee coffee; // 持有一个咖啡对象public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;}@Overridepublic double cost() {return coffee.cost(); // 委托给被装饰的咖啡对象}@Overridepublic String ingredients() {return coffee.ingredients(); // 委托给被装饰的咖啡对象}
}// 装饰器1:添加牛奶
public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic double cost() {return coffee.cost() + 2.0; // 加牛奶的价格}@Overridepublic String ingredients() {return coffee.ingredients() + ", Milk"; // 牛奶的配料}
}// 装饰器2:添加糖
public class SugarDecorator extends CoffeeDecorator {public SugarDecorator(Coffee coffee) {super(coffee);}@Overridepublic double cost() {return coffee.cost() + 1.0; // 加糖的价格}@Overridepublic String ingredients() {return coffee.ingredients() + ", Sugar"; // 糖的配料}
}public class Client {public static void main(String[] args) {// 创建一个黑咖啡Coffee coffee = new BlackCoffee();System.out.println("Cost: " + coffee.cost()); // 输出:5.0System.out.println("Ingredients: " + coffee.ingredients()); // 输出:Black Coffee// 给黑咖啡添加牛奶coffee = new MilkDecorator(coffee);System.out.println("Cost: " + coffee.cost()); // 输出:7.0System.out.println("Ingredients: " + coffee.ingredients()); // 输出:Black Coffee, Milk// 给已经添加牛奶的咖啡再添加糖coffee = new SugarDecorator(coffee);System.out.println("Cost: " + coffee.cost()); // 输出:8.0System.out.println("Ingredients: " + coffee.ingredients()); // 输出:Black Coffee, Milk, Sugar}
}
解释:
- Component(Coffee):定义了咖啡的基础功能,所有的咖啡类都实现了这个接口,提供
cost()
和ingredients()
方法。 - ConcreteComponent(BlackCoffee):表示一种具体的咖啡(黑咖啡),实现了
Coffee
接口。 - Decorator(CoffeeDecorator):是一个抽象类,持有一个
Coffee
对象,允许在此基础上添加新功能。 - ConcreteDecorator(MilkDecorator 和 SugarDecorator):具体装饰器,分别为咖啡添加牛奶和糖。它们在原有功能的基础上进行扩展。
装饰器模式的优缺点:
优点:
- 增强灵活性:装饰器模式允许动态地向对象添加功能,而不需要修改原有对象的代码。这种方式比继承更灵活。
- 减少子类的创建:通过装饰器模式,我们不需要为每一种不同的组合创建一个子类,而是通过不同的装饰器组合出所需的功能。
- 符合开闭原则:装饰器模式遵循开闭原则,即可以对功能进行扩展而不需要修改原有代码。
缺点:
- 装饰器过多时,系统会变得很复杂:如果装饰器链太长,可能会造成代码的复杂度增加,使得调试和理解变得更加困难。
- 可能导致过多的小对象:每个装饰器本身就是一个对象,因此在复杂的系统中,可能会创建大量的小对象,增加内存开销。
总结:
装饰器模式通过将功能与对象的实现分离,使得我们能够在运行时动态地增加对象的功能,而不需要修改对象本身。它能够灵活地扩展对象功能,减少了子类数量,提升了系统的灵活性和可维护性。