设计模式
前言
提示:我是彩笔,所以能理解菜的人的感受。这些都在心路历程中,不想看的可跳过。
结构型模式
一、装饰器模式(2023/12/27)
1. 解决的需求
在不改变对象结构的情况下动态的添加功能或责任
2. 心路历程
假定我们现在要实现四个类,普通咖啡(5元),加了糖(2元)的普通咖啡,加了奶(3元)的普通咖啡,既加糖又加奶的普通咖啡。我们应该怎么做才能更好地复用呢?
class SimpleCoffee{
public int cost(){
return 5;
}
}
class SugerCoffee{
public int cost(){
return 5+2;
}
}
class MilkCoffee{
public int cost(){
return 5+3;
}
}
class SugerAndMilkCoffee{
public int cost(){
return 5+3+2;
}
}
但凡在多加一个种类,比如椰果,会发现类的数量呈指数增长。所以要优化
步骤一: 消除重复代码
class SimpleCoffee {
public int cost(){
return 5;
}
}
class sugerCoffee extends SimpleCoffee{
@Override
public int cost(){
return super.cost() + 2;
}
}
class MilkCoffee extends SimpleCoffee {
@Override
public int cost() {
return super.cost() + 3;
}
}
class SugarAndMilkCoffee extends SimpleCoffee {
@Override
public int cost() {
return super.cost() + 3 + 2;
}
}
在这一步中,我们通过让SugarCoffee、MilkCoffee和SugarAndMilkCoffee扩展SimpleCoffee,消除了一些重复代码。现在,它们继承了SimpleCoffee的基本成本,并添加了各自的特定成本。
步骤2:引入接口
interface Coffee{
int cost();
}
class SimpleCoffee implements Coffee{
@Override
public int cost(){
return 5;
}
}
class SugerCoffee implements Coffee{
private final Coffee coffee;
public SugerCoffee(Coffee coffee){
this.coffee = coffee;
}
@Override
public int cost(){
return coffee.cost() + 2;
}
}
class MilkCoffee extends SimpleCoffee {
private final Coffee coffee;
public MilkCoffee(Coffee coffee) {
this.coffee = coffee;
}
@Override
public int cost() {
return coffee.cost() + 3;
}
}
class SugarAndMilkCoffee extends SimpleCoffee {
private final Coffee coffee;
public SugarAndMilkCoffee(Coffee coffee) {
this.coffee = coffee;
}
@Override
public int cost() {
return coffee.cost() + 3 + 2;
}
}
现在,我们引入了Coffee接口,每种咖啡类型都实现了该接口。我们还为每个类添加了构造函数,以组合基本咖啡的成本。
将private final Coffee coffee; 添加到MilkCoffee 类中是为了引入一种称为组合的设计模式。这是为了使MilkCoffee 可以包含另一种 Coffee 对象,并在其基础上添加额外的功能(在这个例子中是添加牛奶的成本)。
步骤3:分离关注点
3. 最终示例代码
interface Coffee {
int cost();
}
class SimpleCoffee implements Coffee {
@Override
public int cost() {
return 5;
}
}
abstract class CoffeeDecorator implements Coffee {
private final Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public int cost() {
return coffee.cost();
}
}
class SugarCoffee extends CoffeeDecorator {
public SugarCoffee(Coffee coffee) {
super(coffee);
}
@Override
public int cost() {
return super.cost() + 2;
}
}
class MilkCoffee extends CoffeeDecorator {
public MilkCoffee(Coffee coffee) {
super(coffee);
}
@Override
public int cost() {
return super.cost() + 3;
}
}
在这一步中,我们引入了CoffeeDecorator抽象类,它实现了Coffee接口,并包含了一个Coffee实例。这样,我们可以在具体的装饰器类中扩展咖啡的成本,而不影响基本咖啡类。
让我们解释一下这个设计:
-
接口 Coffee: 定义了 cost() 方法,表示咖啡的成本。
-
基本咖啡类 SimpleCoffee: 实现了 Coffee 接口,表示没有额外成本的基本咖啡。
-
装饰器抽象类 CoffeeDecorator: 实现了 Coffee 接口,包含一个 Coffee 对象作为成员变量,通过组合来扩展基础咖啡的功能。
-
具体装饰器类 MilkCoffee: 继承了 CoffeeDecorator,并通过构造函数接收另一个 Coffee 对象(即被装饰的咖啡),然后在 cost() 方法中添加额外的成本(牛奶的成本)。
通过这样的设计,我们可以轻松地组合不同的装饰器,以获得不同组合的咖啡,而不需要修改基础咖啡类或其他装饰器类。这符合开放/封闭原则,即对修改关闭,对扩展开放。
总结
提示:距离总结还有一会