我已经学会了这两种模式但却不理解这两种模式之间的差异。
我不知道场景,何时何地使用这些模式。
任何人都可以解释差异和用例吗?
答案 0 :(得分:17)
主要区别在于策略模式封装了一组相关行为,而访客模式封装了多个此类组。
答案 1 :(得分:3)
访客模式用于遍历对象层次结构并提供一些功能,如打印或报告等。我使用它来提供不同的格式(文本/ HTML),通过编写多个访问者来打印对象层次结构,每个访问者对应一种格式。层次结构中的对象是可访问的对象。
策略模式用于根据输入选择特定的逻辑路径。一个典型的例子是身份验证过滤器,根据Authorization
HTTP标头中的值,选择并运行不同的身份验证策略,如NTLM / Negotiate / Basic。过滤器将保留对AuthenticationStrategy接口的引用,基于传入请求,选择特定的身份验证策略并将其分配给此引用,后面的代码不需要知道正在使用的策略。
答案 2 :(得分:2)
访客模式意图:
表示要对对象结构的元素执行的操作。访问者允许您定义新操作,而无需更改其操作的元素的类。
在以下情况下使用访问者模式:
尽管访问者模式提供了在不更改Object中现有代码的情况下添加新操作的灵活性,但这种灵活性还存在缺陷。
如果添加了新的Visitable对象,则需要在Visitor&amp ;;中更改代码。 ConcreteVisitor类。有一种解决方法可以解决此问题:使用反射,这将对性能产生影响。
有关详细信息,请参阅oodesign article和sourcemaking文章
策略模式意图:
定义一系列算法,封装每个算法,并使它们可互换。策略允许算法独立于使用它的客户端。
策略可让您更改对象的内容。
有关详细信息,请参阅以下SE问题:
答案 3 :(得分:0)
除了上面提到的行为差异之外,我在处理项目期间的依赖关系和用例方面也遇到了不同,如下所示。
例如,Visitor知道具体的类。因此,在向层次结构添加新的具体类时,以更改访问者代码为代价,您将更加灵活。战略中没有这样的东西。在这种情况下,如果您只使用给定输入返回某些输出的方法,则策略变得更合适。无论上下文如何。
此外,访客模式也用于实施SOLID的SRP,以分离关注点。
答案 4 :(得分:0)
访问者适用于您拥有一系列课程,并且您需要为该系列中的每个课程添加新功能,但不要自行触摸课程(或希望将所有新功能都添加到一个地方 - 访客)
策略适用于您有一系列需要能够正常工作才能正常工作的类(例如对其中包含的某些对象进行排序),但您希望客户端或您的依赖性注射告诉他们这样做的方法。
答案 5 :(得分:0)
想象一下,您正在构建一个用于创建收据的收银应用。假设您要:
1.确保对不同种类的物品(书籍,水果,肉,洗漱用品等)进行不同的处理
2.将实际计算价格的逻辑与项目定义分开
3.确保如果商店开始销售全新的商品(假设布料将按长度收费),则无需更改太多代码
访问者可以是一个类,它根据要处理的项目类型定义不同的计算类型。这是一项服务,可以消除价格计算中的差异,而不会导致商品层次结构的变化。
getPrice
的正文如下:
getPrice(Calculation c) {
return c.calculate(this); // <-- visitor.visit( specific implementation )
}
,然后说ShoppingCart
,您将这样做:
calc = getPriceCalculator()
foreach item in items:
totalPrice += item.getPrice(calc)
想象一下这种情况:在黑色星期五,您想进行一些疯狂的折扣,所有书籍减价70%,所有水果减价50%。您可以轻松地执行以下操作:
BlackFridayCalculator extends PriceCalculator {
calculate(Book b) { return 0.3 * parent.calculate(b) }
calculate(Fruit f) { return 0.5 * parent.calculate(f) }
}
// and in getPriceCalculator:
return (black friday time) ? new BlackFridayCalculator() : new PriceCalculator();
相反,策略可以具有不同类型的计算(策略)的层次结构,然后每个项目都将定义,应使用哪种计算(策略)(“插入”)。
现在有很多方法可以定义应该使用哪种计算的项目。最简单的方法是提供Item
方法getCalculator
,然后让每个项目选择所需的计算方式。
这可能不太动态-从某种意义上说,每个项目都需要有一个将要使用的预定义计算器。但是,请考虑以下情况:商店的老板决定菠萝和西瓜应按每件出售-我们可以很容易地让Fruit
默认使用WeightCalculator
并创建一部分要按数量出售的水果