装饰类 java,装饰器方法,Java中的一种装饰器类型

博主在学习使用装饰者模式时遇到问题,如何避免一个咖啡实例多次添加同类型调料(如美国咖啡加两次 Soy)。讨论了可能的解决方案,包括检查已有的装饰类型、使用反射或解析描述等,同时指出设计上的权衡与开放封闭原则的挑战。
摘要由CSDN通过智能技术生成

just in the process of learning to use the decorator pattern, and ran into a problem which I reckon is simple but I can't seem to find the answer to.

Lets say I have a Beverage class that's abstract. Then lets say I have a few concrete components extending Beverage, americano, espresso, latte etc. And also an abstract Condiment class extending Beverage. Condiments then has multiple subclasses milk, sugar, soy, whip. Each of the condiment subclasses have a cost and getdescription() method inherited from Beverage and Condiments respectively. My question is how when testing, do I stop a certain Beverage instance having more than one condiment of the same type associated with it, i.e an americano getting charged for soy only once,even if soy was stated twice in the test class. I know that I could save a condiment into a list and check if it exists when adding a new condiment, but just wanted to see if a better option existed.

Beverage class

package designpatterns.decorator.coffee;

public abstract class Beverage {

String description = "Unknown Beverage";

public String getDescription() {

return description;

}

public abstract double cost();

}

Condiment Decorator

package designpatterns.decorator.coffee;

public abstract class CondimentDecorator extends Beverage {

public abstract String getDescription();

}

DarkRoast Class

package designpatterns.decorator.coffee;

public class DarkRoast extends Beverage {

public DarkRoast() {

description = "Dark Roast Coffee";

}

public double cost() {

return .99;

}

}

Soy class

package designpatterns.decorator.coffee;

public class Soy extends CondimentDecorator {

Beverage beverage;

public Soy(Beverage beverage) {

this.beverage = beverage;

}

public String getDescription() {

return beverage.getDescription() + ", Soy";

}

public double cost() {

return .15 + beverage.cost();

}

}

If anyone could help or even point me to a good article or tutorial I would greatly appreciate it.

解决方案

Sounds like the example from Head First Design Patterns (HFDP)? The test case is simple to understand, but the way to do may not be so much.

Think of Decorators as Wrappers. When a decorator is about to wrap something, it could check that "thing" to see if it contains already a decorator of its own type. Here's code from HFDP that I changed slightly:

Beverage beverage2 = new DarkRoast();

beverage2 = new Mocha(beverage2);

beverage2 = new Soy(beverage2); // wrap once

beverage2 = new Soy(beverage2); // wrap again (**error case)

You'd have to decide if you want to disallow multiple wrapping for all decorators, or perhaps some decorators can have a kind of "once only" attribute. Another thing to decide is whether to fail (throw an exception) if a second wrap occurs (the ** in the comment above) or if you want to just ignore the extra wraps in cost().

It's probably cleaner and less bug-prone if you stop multiple wrapping at wrap-time. That would be in the constructor. You could code a general function in the abstract class that checks this using reflection (won't work in languages that don't support it), or parses the descriptions of the wrapped object to find its own string (less reliable if decorations don't have unique names).

The biggest problem I see with doing this is that Condiments wrap Beverages, and by design (information hiding), condiments don't "know" they're wrapping other condiments. Any code you write will be possibly fragile (it might violate the open-closed principle). Such are the trade-offs in design, however. You can't have everything, so decide what's more important (stopping multiple wraps, or having a design that allows adding new decorators without breaking anything).

c9cae2f1b129633449e27233de90bec0.png

Using the getDescription (parsing it) would make the most sense, probably, provided you can rely on the format to identify nestings.

The Soy class could do this:

private String myDescription = "Soy"

public Soy(Beverage beverage) {

if (beverage.getDescription().contains(myDescription)) {

throw new Exception();

}

this.beverage = beverage;

}

But a better way might be to .split() on the "," character and check those strings, since descriptions are just concatenations using commas (in getDescription()).

As I said, if it's a general rule to disallow all multiple condiment wraps, you could refactor this logic up to the CondimentDecorator class to avoid duplicated code. You could even have Decorator boolean attribute to say "allowsMultiple" and code that.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值