java 装饰者模式

2023-05-11  本文已影响0人  饱饱想要的灵感

装饰者模式是一种结构型设计模式,它允许你在运行时动态地修改对象的行为。在这种模式中,你可以通过将对象包装在一个装饰器对象中来添加新的行为,而不是修改原始对象的代码。

一、实现思路

在Java中,装饰者模式可以通过继承和组合来实现。通过创建一个包装器对象来实现的,该对象包装了原始对象,并在其上添加了新的行为或功能。步骤如下:

  1. 定义一个抽象组件(Component)类,它是被装饰者和装饰者的公共接口,可以是一个抽象类或接口。
  2. 定义一个具体组件(ConcreteComponent)类,它是抽象组件的实现类。
  3. 定义一个抽象装饰者(Decorator)类,它也是抽象组件的子类,它包含一个抽象组件类型的成员变量,以及一个构造方法,用于初始化该成员变量。
  4. 定义一个具体装饰者(ConcreteDecorator)类,它是抽象装饰者的实现类,它重写了抽象装饰者的方法,并在其中调用了被装饰者的方法,同时还可以添加自己的行为。

二、简单示例

下面是一个简单的示例,演示如何使用装饰者模式来动态地添加新的行为。

首先,我们定义一个接口Component,它是所有组件的基类:

public interface Component {
    void operation();
}

然后,我们定义一个具体的组件ConcreteComponent,它实现了Component接口:

public class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent operation");
    }
}

现在,我们可以定义一个装饰器Decorator,它也实现了Component接口,并且包含一个Component类型的成员变量,用于存储被装饰的对象:

public abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

注意,Decorator是一个抽象类,它的operation()方法调用了被装饰对象的operation()方法。

接着,我们可以定义具体的装饰器ConcreteDecorator,它继承自Decorator,并且可以添加新的行为:

public class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        System.out.println("ConcreteDecorator operation");
    }
}

最后,我们可以使用装饰器模式来创建一个具有新行为的对象:

Component component = new ConcreteComponent();
component.operation(); // 输出 "ConcreteComponent operation"

Component decoratedComponent = new ConcreteDecorator(component);
decoratedComponent.operation(); // 输出 "ConcreteComponent operation" 和 "ConcreteDecorator operation"

在这个示例中,我们首先创建了一个ConcreteComponent对象,然后使用ConcreteDecorator来装饰它,从而添加了新的行为。当我们调用decoratedComponent的operation()方法时,它会先调用被装饰对象的operation()方法,然后再添加新的行为。

三、咖啡例子

一个经典的例子是咖啡店的咖啡。咖啡店通常会提供多种咖啡,例如浓缩咖啡、拿铁咖啡、卡布奇诺等。每种咖啡都有其基本配方,但客户可以根据自己的口味添加额外的配料,例如牛奶、糖浆、奶泡等。

在这种情况下,咖啡可以看作是一个基本对象,而添加的配料可以看作是装饰器。客户可以根据自己的喜好选择不同的装饰器来定制自己的咖啡。

下面是一个简单的Java代码示例,演示如何使用装饰者模式来制作咖啡。

首先,我们定义一个基本的咖啡接口,它包含了获取咖啡名称和价格的方法:

public interface Coffee {
    String getName();
    double getPrice();
}

然后,我们实现一个基本的浓缩咖啡类,它实现了Coffee接口:

public class Espresso implements Coffee {
    @Override
    public String getName() {
        return "Espresso";
    }

    @Override
    public double getPrice() {
        return 1.99;
    }
}

接下来,我们定义一个装饰器接口,它也实现了Coffee接口,但是它还包含了一个setCoffee方法,用于设置要装饰的咖啡对象:

public interface CoffeeDecorator extends Coffee {
    void setCoffee(Coffee coffee);
}

再然后,我们实现一个牛奶装饰器,它将牛奶添加到咖啡中:

public class MilkDecorator implements CoffeeDecorator {
    private Coffee coffee;

    @Override
    public void setCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String getName() {
        return coffee.getName() + ", Milk";
    }

    @Override
    public double getPrice() {
        return coffee.getPrice() + 0.5;
    }
}

最后,我们可以使用这些类来制作不同的咖啡:

public class CoffeeShop {
    public static void main(String[] args) {
        // 制作一杯浓缩咖啡
        Coffee espresso = new Espresso();
        System.out.println(espresso.getName() + ": $" + espresso.getPrice());

        // 制作一杯加牛奶的浓缩咖啡
        Coffee milkEspresso = new MilkDecorator();
        milkEspresso.setCoffee(new Espresso());
        System.out.println(milkEspresso.getName() + ": $" + milkEspresso.getPrice());

        // 制作一杯加牛奶和糖浆的浓缩咖啡
        Coffee syrupMilkEspresso = new SyrupDecorator();
        syrupMilkEspresso.setCoffee(new MilkDecorator());
        syrupMilkEspresso.getCoffee().setCoffee(new Espresso());
        System.out.println(syrupMilkEspresso.getName() + ": $" + syrupMilkEspresso.getPrice());
    }
}

输出结果如下:

复制代码Espresso: $1.99
Espresso, Milk: $2.49
Espresso, Milk, Syrup: $3.49

这个例子展示了如何使用装饰者模式来动态地添加行为或功能。客户可以根据自己的喜好选择不同的装饰器来定制自己的咖啡,而不需要修改基本的咖啡类。

四、jdk中的应用

Java的IO库中,InputStream和OutputStream是抽象类,它们的子类实现了不同的输入输出方式,如FileInputStream和FileOutputStream、ByteArrayInputStream和ByteArrayOutputStream等。这些子类都是装饰者模式的具体实现。

下面是一个简单的例子,演示了如何使用装饰者模式来实现文件读写操作:

// 创建一个文件输入流
InputStream inputStream = new FileInputStream("test.txt");

// 使用BufferedInputStream装饰文件输入流,添加缓冲功能
InputStream bufferedInputStream = new BufferedInputStream(inputStream);

// 使用DataInputStream装饰BufferedInputStream,添加读取基本数据类型的功能
DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);

// 读取文件中的数据
int num = dataInputStream.readInt();
String str = dataInputStream.readUTF();

// 关闭流
dataInputStream.close();

在这个例子中,我们首先创建了一个文件输入流,然后使用BufferedInputStream装饰它,添加了缓冲功能。接着,我们又使用DataInputStream装饰BufferedInputStream,添加了读取基本数据类型的功能。最后,我们通过DataInputStream读取了文件中的数据,并关闭了流。

这个例子中,我们使用了两个装饰者类来装饰文件输入流,它们分别是BufferedInputStream和DataInputStream。这两个类都是InputStream的子类,同时也是装饰者类。它们的作用是在文件输入流的基础上添加额外的功能,例如缓冲、读取基本数据类型等。

上一篇 下一篇

猜你喜欢

热点阅读