【发布时间】:2016-10-05 20:54:39
【问题描述】:
所以我为液体创建了一个简单的访客模式。如牛奶、果汁和白酒。
Milk 类可以如下所示:
public class Milk implements Visitable{
public float tax=0;
@Override
public int price() {
return 4;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
//果汁和酒类也是如此
然后我们可以让一个看起来像这样的访问者来完成计算税金的工作:
public class TaxVisitor implements Visitor {
double taxPerentLiquor=.18;
double taxPerentMilk=.15;
double taxPerentJuice=.10;
@Override
public void visit(Liquor liquor) {
int price =liquor.price();
liquor.setTax((float) (price*taxPerentLiquor));
}
@Override
public void visit(Milk milk) {
float price =milk.price();
milk.setTax((float) (price*taxPerentMilk));
}
@Override
public void visit(Juice juice) {
int price =juice.price();
juice.setTax((float) (price*taxPerentJuice));
}
}
当我们使用它时,我们会这样做:
Visitor taxVisitor = new TaxVisitor();
Milk milk = new Milk();
Juice juice = new Juice();
milk.accept(taxVisitor);
juice.accept(taxVisitor);
“访客”会为我计算每种液体的税金。我看到了当我想添加新计算时我不必修改对象集合本身的好处。但是当我想添加一个新方法时,我的麻烦就来了。例如,遵循开放封闭原则,我不应该向牛奶类添加新方法。但是让我们想象一下,我想添加功能以了解液体是什么颜色。所以我想扩展牛奶对象以拥有一个名为“getColor()”的方法,该方法将返回“#FFFFFF”。如果我想遵循 SOLID 开放封闭原则,这似乎需要一个装饰器模式来添加此功能。有没有办法通过访问者模式做到这一点?
【问题讨论】:
-
除非您打算存储访问者中每种液体的颜色(就像您对税收所做的那样),否则不会。访问者不会向对象添加行为,它会在对象上执行行为。与您的税务访问者一样,您不会向对象添加行为,您只是根据对象的类型执行行为(这可能会触发对象执行已经存在的行为)
-
我明白了。所以访问者是为了执行行为而不是添加行为。
-
从技术上讲,它确实会添加行为,但不会添加到元素中。这些行为属于元素的族,而不仅仅是一个元素。将其应用于您的情况的问题由您的
TaxVisitor表达:访问者需要维护元素未维护的任何状态。因此,如果没有一种液体保持自己的颜色,ColorVisitor将不得不保持所有这些液体。这是可能的,但不切实际。 -
如果我想在我的元素集合中添加方法(添加元素行为)而不修改它们,你推荐什么模式?
-
在您的液体中添加
getColor()不违反 O/C。这就是“open for extension”的目的:您仍然可以添加行为,只要它们不影响任何现有行为。如果您影响现有代码,任何依赖于它的代码也可能受到影响,这可能会破坏合约(从而破坏软件)。如果添加getColor()不会影响任何工作代码,那么这不是违反原则,而是扩大规模。 Look at the first bullet point from this link
标签: java design-patterns visitor-pattern open-closed-principle