装饰器方法,Java中的一种装饰器类型 [英] Decorator method, one Decorator type in Java

查看:158
本文介绍了装饰器方法,Java中的一种装饰器类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

只是在学习使用装饰图案的过程中,遇到了一个我认为很简单但我似乎找不到答案的问题。
说我有一个抽象的饮料类。然后让我说,我有几个具体的组件,延伸饮料,美洲,浓缩咖啡,拿铁等。还有一个抽象的调味品类延伸饮料。调味品然后有多个子类牛奶,糖,大豆,鞭子。每个调味品子类分别具有从饮料和调味品继承的成本和getdescription()方法。我的问题是如何在测试时停止某一饮料实例,它具有与其相同类型的多种调味品,即美国大豆只收取一次,即使大豆在测试课中被提及两次。我知道我可以将调味品保存在清单中,并检查添加新调味品是否存在,但只是想看看是否有更好的选择。



饮料类

  package designpatterns.decorator.coffee; 


public abstract class Beverage {


String description =Unknown Beverage;



public String getDescription(){

return description;

}



public abstract double cost();


}

调味品装饰师

  package designpatterns.decorator.coffee; 

public abstract class CondimentDecorator extends Beverage {

public abstract String getDescription();

}

DarkRoast类

  package designpatterns.decorator.coffee; 


public class DarkRoast扩展饮料{

public DarkRoast(){

description =黑咖啡

}



public double cost(){

return .99;

}

}

大豆类

  package designpatterns.decorator.coffee; 


公共类大豆延伸CondimentDecorator {

饮料饮料;



公共大豆(饮料饮料){

this.beverage =饮料;

}



public String getDescription(){

return beverage.getDescription()+,Soy ;


}



public double cost(){

return .15 + beverage.cost ();
}

}

如果有人可以帮助甚至点我很好的文章或教程我将非常感激。

解决方案

听起来像头部设计模式(HFDP)?测试用例很容易理解,但是做的方式可能不会太多。



想到装饰器是包装器。当装饰器即将包装时,它可以检查事物,看它是否包含自己类型的装饰器。以下是HFDP的代码,我略有改变:

 饮料drink2 =新的DarkRoast(); 
drinks2 =新的摩卡(饮料2);
drinks2 =新大豆(drink2); //换一次
drinks2 = new大豆(drink2); // wrap again(** error case)

你必须决定是否不允许所有装饰器的多重包装,或者一些装饰器可以有一种一次属性。另一件事是要是是否发生第二次换行(抛出异常)(上面的注释中的**),或者如果你想忽略 cost()



如果您在封换时停止多个包装,那么它可能更清洁,更少错误。那将在构造函数中。您可以在抽象类中编写一个通用函数,使用反射来检查这个函数(在不支持它的语言中将不起作用),或者解析包装对象的描述以找到自己的字符串(如果装饰不太可靠, t / b

我看到的最大的问题是调味品包装饮料和设计(信息隐藏),调味品不知道他们正在包装其他调味品。你编写的任何代码都可能很脆弱(可能违反开放原则)。然而,这是设计中的权衡。你不能拥有一切,所以决定什么更重要(停止多个包装,或设计允许添加新的装饰器,而不会破坏任何东西)。





使用getDescription (解析它)最有意义的是,只要你可以依靠格式来识别嵌套。



大豆类可以这样做:

  private String myDescription =Soy
public Soy(饮料饮料){
if(beverage.getDescription() (myDescription)){
throw new Exception();
}
this.beverage =饮料;
}

但更好的方法可能是 .split )中的,字符,并检查这些字符串,因为描述只是使用逗号连接(在 getDescription())。



正如我所说,如果禁止所有多个调味品包装是一般规则,您可以将此逻辑重构为CondimentDecorator类,以避免重复的代码。你甚至可以使用Decorator布尔属性来表示allowMultiple并代码。


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).

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.

这篇关于装饰器方法,Java中的一种装饰器类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆