dot*_*tep 33 oop design-patterns
我无法理解这两种设计模式.
你能不能给我一些背景信息或一个例子,这样我就可以得到一个清晰的想法,并能够映射出他们两者之间的差异.
谢谢.


aho*_*fer 84
这是我看待它的方式.该策略模式就像是一个一对多的关系.当有一种类型的对象并且我想对它应用多个操作时,我使用策略模式.例如,如果我有一个封装视频剪辑的Video类,我可能想以不同的方式压缩它.所以我创建了一堆策略类:
MpegCompression
AviCompression
QuickTimeCompression
Run Code Online (Sandbox Code Playgroud)
等等.
我认为访客模式是很多:许多关系.假设我的应用程序不仅包括视频,还包括音频剪辑.如果我坚持使用策略模式,我必须复制我的压缩类 - 一个用于视频,一个用于音频:
MpegVideoCompression
MpegAudioCompression
Run Code Online (Sandbox Code Playgroud)
等等...
如果我切换到访问者模式,我不必复制策略类.我通过添加方法实现了我的目标:
MpegCompression::compressVideo(Video object)
MpegCompression::compressAudio(Audio object)
Run Code Online (Sandbox Code Playgroud)
小智 12
策略模式用于将各种算法暴露给标准化接口.一个典型的例子可以是一个排序实用程序,它允许用户(程序员)在各种排序算法之间进行选择,每个排序算法都通过相同的接口调
访客模式生活在不同的层面.它详细说明了一种机制,通过该机制,对象可以接受对另一个对象(访问者)的引用,该对象公开了目标对象可以调用的预定接口.当然,不同的访问者会呈现相同的界面但具有不同的实现.
即将回到我们的例子中,排序算法的集合,既可以通过策略模式或通过访问者模式来实现.
使用Strategy方法,每个算法呈现相同的接口,并将目标对象的数组作为参数.与访问者模式,这将是在目标阵列,是以"访问"算法作为参数.在这种情况下,目标将"接受()"选定的访问者,并在我们的示例中调用目标的排序方法时调用其"visit()"方法.
同一枚硬币的两面......
这有意义吗?
访问者是一种策略,但有多种方法,它允许双重调度。访问者还允许在运行时在两个具体对象之间进行安全绑定。
注意:这是一个用 Java 编写的示例。例如 C# 引入了dynamic关键字,因此双分派的例子在 C# 中没有用。
考虑以下示例和输出:
package DesignPatterns;
public class CarGarageStrategyDemo
{
public static interface RepairStrategy
{
public void repair(Car car);
}
public static interface Car
{
public String getName();
public void repair(RepairStrategy repairStrategy);
}
public static class PorscheRepairStrategy implements RepairStrategy
{
@Override
public void repair(Car car) {
System.out.println("Repairing " + car.getName() + " with the Porsche repair strategy");
}
}
public static class FerrariRepairStrategy implements RepairStrategy
{
@Override
public void repair(Car car) {
System.out.println("Repairing " + car.getName() + " with the Ferrari repair strategy");
}
}
public static class Porsche implements Car
{
public String getName()
{
return "Porsche";
}
@Override
public void repair(RepairStrategy repairStrategy) {
repairStrategy.repair(this);
}
}
public static void main(String[] args)
{
Car porsche = new Porsche();
porsche.repair(new PorscheRepairStrategy()); //Repairing Porsche with the porsche repair strategy
}
}
Run Code Online (Sandbox Code Playgroud)
Strategy如果策略和主题之间没有直接关系,则该模式工作正常。例如,我们不希望发生以下情况:
...
public static void main(String[] args)
{
Car porsche = new Porsche();
porsche.repair(new FerrariRepairStrategy()); //We cannot repair a Porsche as a Ferrari!
}
...
Run Code Online (Sandbox Code Playgroud)
所以在这种情况下,我们可以使用访问者模式。
考虑下面的代码:
public class CarGarageVisitorProblem
{
public static interface Car
{
public String getName();
}
public static class Porsche implements Car
{
public String getName()
{
return "Porsche";
}
}
public static class Ferrari implements Car
{
public String getName()
{
return "Ferrari";
}
}
public void repair(Car car)
{
System.out.println("Applying a very generic and abstract repair");
}
public void repair(Porsche car)
{
System.out.println("Applying a very specific Porsche repair");
}
public void repair(Ferrari car)
{
System.out.println("Applying a very specific Ferrari repair");
}
public static void main(String[] args)
{
CarGarageVisitorProblem garage = new CarGarageVisitorProblem();
Porsche porsche = new Porsche();
garage.repair(porsche); //Applying a very specific Porsche repair
}
}
Run Code Online (Sandbox Code Playgroud)
输出是Applying a very specific Porsche repair。问题是这条线不是抽象的,而是具体的:
Porsche porsche = new Porsche();
Run Code Online (Sandbox Code Playgroud)
我们想把它写成(或者在构造函数中注入一个 Car 的实例,我们想应用Dependency Inversion Principle):
Car porsche = new Porsche();
Run Code Online (Sandbox Code Playgroud)
但是当我们改变这一行时,输出将是:
Applying a very generic and abstract repair
Run Code Online (Sandbox Code Playgroud)
不是我们想要的!
Applying a very generic and abstract repair
Run Code Online (Sandbox Code Playgroud)
由于方法重载,访问者和主题(汽车)之间存在具体绑定。保时捷无法像法拉利一样修理,因为它使用方法重载。我们还Dependency Inversion通过实现此方法解决了先前解释的问题(我们不能使用):
package DesignPatterns;
public class CarGarageVisitorExample
{
public static interface Car
{
public String getName();
public void repair(RepairVisitorInterface repairVisitor);
}
public static class Porsche implements Car
{
public String getName()
{
return "Porsche";
}
public void repair(RepairVisitorInterface repairVisitor)
{
repairVisitor.repair(this);
}
}
public static class Ferrari implements Car
{
public String getName()
{
return "Ferrari";
}
public void repair(RepairVisitorInterface repairVisitor)
{
repairVisitor.repair(this);
}
}
public static interface RepairVisitorInterface
{
public void repair(Car car);
public void repair(Porsche car);
public void repair(Ferrari car);
}
public static class RepairVisitor implements RepairVisitorInterface
{
public void repair(Car car)
{
System.out.println("Applying a very generic and abstract repair");
}
public void repair(Porsche car)
{
System.out.println("Applying a very specific Porsche repair");
}
public void repair(Ferrari car)
{
System.out.println("Applying a very specific Ferrari repair");
}
}
public static void main(String[] args)
{
CarGarageVisitor garage = new CarGarageVisitor();
Car porsche = new Porsche();
porsche.repair(new RepairVisitor()); //Applying a very specific Porsche repair
}
}
Run Code Online (Sandbox Code Playgroud)
该this参考将返回对象,而不是抽象(CAR)类型的具体类型。
访客就像一夜情 - 你在调用accept函数时创建它然后它们被分开并且访问者可以从内存中清除,它不会为使用它的类占用任何空间.
这个策略就像一场婚姻 - 你创造了一个对象,它生活在使用它的类中,占用记忆,有一个房间,并在早上让自己变成咖啡:).当然,他们可以离婚并转换到另一个班级,但该班级也会生活在其所有者的背景下.
希望它能帮助你记住:)