装饰器设计模式示例

本文深入探讨了Java中的装饰器设计模式,解释了其在动态扩展对象功能而不修改原始类结构方面的重要性。通过实例展示了如何在Java中实现装饰器模式,特别是在为披萨添加额外配料的场景中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文是我们名为“ Java设计模式 ”的学院课程的一部分。

在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看

1.简介

要了解装饰器设计模式,让我们帮助比萨公司制作一个额外的打顶计算器。 用户可以要求向披萨添加额外的配料,而我们的工作是使用该系统添加配料并提高其价格。

这就像在运行时为我们的披萨对象增加了额外的责任,Decorator Design Pattern适用于此类需求。 但是在此之前,让我们进一步了解这种美丽的图案。

2.什么是装饰器设计模式

装饰器设计模式的目的是动态地将附加职责附加到对象上。 装饰器提供了子类别的灵活替代方案,以扩展功能。

装饰器模式用于动态扩展对象的功能,而无需更改原始类的源或使用继承。 这是通过在实际对象周围创建一个称为Decorator的对象包装来完成的。

Decorator对象设计为具有与基础对象相同的接口。 这允许客户端对象与Decorator对象进行交互,其方式与与基础实际对象进行交互的方式完全相同。 Decorator对象包含对实际对象的引用。 Decorator对象接收来自客户端的所有请求(调用)。 反过来,它将这些调用转发到基础对象。 Decorator对象在将请求转发到基础对象之前或之后添加了一些其他功能。 这确保了可以在运行时从外部将附加功能添加到给定对象,而无需修改其结构。

装饰器可防止子类的泛滥,从而减少复杂性和混乱。 添加功能的任意组合都很容易。 相同的功能甚至可以添加两次。 对于给定的对象,可以同时具有不同的装饰器对象。 客户端可以通过将消息发送到适当的装饰器来选择所需的功能。

decorator_design_pattern_class_diagram_1

图1-类图

零件

  • 为可以动态添加职责的对象定义接口。

混凝土构件

  • 定义可以附加其他职责的对象。

装饰器

  • 维护对Component对象的引用,并定义一个符合Component接口的接口。

混凝土装饰工

  • 向组件添加责任。

3.实施装饰器设计模式

为简单起见,让我们创建一个仅包含两个方法的简单Pizza接口。

package com.javacodegeeks.patterns.decoratorpattern;

public interface Pizza {

	public String getDesc();
	public double getPrice();
}

getDesc方法用于获取披萨的说明,而getPrice用于获取价格。

以下是两个具体的Pizza类:

package com.javacodegeeks.patterns.decoratorpattern;

public class SimplyVegPizza implements Pizza{

	@Override
	public String getDesc() {
		return "SimplyVegPizza (230)";
	}
	
	@Override
	public double getPrice() {
		return 230;
	}


}
package com.javacodegeeks.patterns.decoratorpattern;

public class SimplyNonVegPizza implements Pizza{
	
	@Override
	public String getDesc() {
		return "SimplyNonVegPizza (350)";
	}

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

}

装饰器包装需要增加功能的对象,因此需要实现相同的接口。 下面是一个抽象装饰器类,它将由所有具体装饰器扩展。

package com.javacodegeeks.patterns.decoratorpattern;

public abstract class PizzaDecorator implements Pizza {
	
	@Override
	public String getDesc() {
		return "Toppings";
	}

}

以下是具体的装饰器类。

package com.javacodegeeks.patterns.decoratorpattern;

public class Broccoli extends PizzaDecorator{

	private final Pizza pizza;
	
	public Broccoli(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Broccoli (9.25)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+9.25;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class Cheese extends PizzaDecorator{

	private final Pizza pizza;
	
	public Cheese(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Cheese (20.72)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+20.72;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class Chicken extends PizzaDecorator{

	private final Pizza pizza;
	
	public Chicken(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Chicken (12.75)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+12.75;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class FetaCheese extends PizzaDecorator{

	private final Pizza pizza;
	
	public FetaCheese(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Feta Cheese (25.88)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+25.88;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class GreenOlives extends PizzaDecorator{

	private final Pizza pizza;
	
	public GreenOlives(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Green Olives (5.47)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+5.47;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class Ham extends PizzaDecorator{

	private final Pizza pizza;
	
	public Ham(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Ham (18.12)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+18.12;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class Meat extends PizzaDecorator{

	private final Pizza pizza;
	
	public Meat(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Meat (14.25)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+14.25;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class RedOnions extends PizzaDecorator{

	private final Pizza pizza;
	
	public RedOnions(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Red Onions (3.75)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+3.75;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class RomaTomatoes extends PizzaDecorator{

	private final Pizza pizza;
	
	public RomaTomatoes(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Roma Tomatoes (5.20)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+5.20;
	}

}
package com.javacodegeeks.patterns.decoratorpattern;

public class Spinach extends PizzaDecorator{

	private final Pizza pizza;
	
	public Spinach(Pizza pizza){
		this.pizza = pizza;
	}

	@Override
	public String getDesc() {
		return pizza.getDesc()+", Spinach (7.92)";
	}


	@Override
	public double getPrice() {
		return pizza.getPrice()+7.92;
	}

}

我们需要用这些浇头装饰披萨对象。 上面的类包含对需要装饰的披萨对象的引用。 装饰器对象在调用装饰器的函数后将其功能添加到装饰器。

package com.javacodegeeks.patterns.decoratorpattern;

import java.text.DecimalFormat;

public class TestDecoratorPattern {
	
	public static void main(String[] args) {
		
		DecimalFormat dformat = new DecimalFormat("#.##");
		Pizza pizza = new SimplyVegPizza();
		
		pizza = new RomaTomatoes(pizza);
		pizza = new GreenOlives(pizza);
		pizza = new Spinach(pizza);
		
		System.out.println("Desc: "+pizza.getDesc());
		System.out.println("Price: "+dformat.format(pizza.getPrice()));
		
		pizza = new SimplyNonVegPizza();
		
		pizza = new Meat(pizza);
		pizza = new Cheese(pizza);
		pizza = new Cheese(pizza);
		pizza = new Ham(pizza);
		
		System.out.println("Desc: "+pizza.getDesc());
		System.out.println("Price: "+dformat.format(pizza.getPrice()));
	}

}

上面的代码将产生以下输出:

Desc: SimplyVegPizza (230), Roma Tomatoes (5.20), Green Olives (5.47), Spinach (7.92)
Price: 248.59
Desc: SimplyNonVegPizza (350), Meat (14.25), Cheese (20.72), Cheese (20.72), Ham (18.12)
Price: 423.81

在上面的类中,我们首先创建了SimplyVegPizza ,然后用RomaTomatoesGreenOlivesSpinach装饰它。 输出中的desc显示添加在SimplyVegPizza中的浇头,且价格为所有价格的总和。

我们对SimplyNonVegPizza做了同样的事情,并在SimplyNonVegPizza添加了不同的SimplyNonVegPizza 。 请注意,您可以为一个对象多次装饰同一件事。 在上面的示例中,我们两次添加了cheese ; 它的价格也增加了两倍,可以在输出中看到。

当您需要在运行时为对象添加额外功能并对其进行修改时,Decorator设计模式看起来不错。 但这会导致很多小物体。 使用Decorator的设计通常会导致系统由许多看起来相似的小对象组成。 对象的区别仅在于它们的互连方式不同,不在于它们的类或变量的值。 尽管这些系统很容易被理解它们的人定制,但是它们可能很难学习和调试。

4.何时使用装饰设计模式

在以下情况下,请使用Decorator模式:

    • 动态透明地向单个对象添加职责,即不影响其他对象。
    • 对于可以撤消的责任。
    • 当通过子类扩展不可行时。 有时可能会有大量独立的扩展,并且会产生大量的子类来支持每种组合。 或者,类定义可能被隐藏或无法用于子类化。

5. Java中的装饰器设计模式

      • java.io.BufferedInputStream(InputStream)
      • java.io.DataInputStream(InputStream)
      • java.io.BufferedOutputStream(OutputStream)
      • java.util.zip.ZipOutputStream(OutputStream)
      • java.util.Collections#checked[List|Map|Set|SortedSet|SortedMap]()

6.下载源代码

这是关于装饰设计模式的课程。

您可以在此处下载相关的源代码: DecoratorPattern-Project

翻译自: https://www.javacodegeeks.com/2015/09/decorator-design-pattern.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值