- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我目前正在自学设计模式。当我研究策略模式时,我发现了一些对我来说看起来很奇怪的东西。我寻找有关此模式的讨论,但没有人回答我的问题……我如何实现策略模式以使其干净、保持封装并使添加新策略变得容易。在这里解释我的问题是“规范”策略模式:
public interface Strategy {
public void run();
}
public class stratConcrt1 implements Strategy {/*run() implementation*/}
public class stratConcrt2 implements Strategy {/*run() implementation*/}
public class Context {
private Strategy strategy;
public Context(Strategy strat) {
this.strategy = strat;
}
public void runStrategy() {
this.strategy.run()
}
}
public class Client {
public void main(Strings[] args) {
Context cx;
cx = new Context(new stratConcrt1())
cx.runStrategy();
cx = new Context(new stratConcrt2())
cx.runStrategy();
}
}
我明白这是怎么回事,但让客户知道一些可以应用的不同策略我觉得很奇怪。对我来说,让 Context 实例化不同的策略而不是 Client 会更清晰,因为 Context 处理策略它应该(至少在我看来)是唯一能够实例化策略的策略。
我使用 JavaFx 实现了一个小示例,但与上面的代码有一些不同:
我有一个实例化坐标列表的类 Field,这个类有一个对列表进行排序的方法。对坐标列表进行排序的方法是有多种策略的方法。
public class Field {
// a field contains rectangles described in a list through their coordinates
private ObservableList<Coordinate> mpv_coordinateList = FXCollections
.observableArrayList();
private Context mpv_sortContext;
// Constructor
public Field() {
//the rectangles are randomly created
Random rd = new Random();
for (int i = 0; i < 100; i++) {
mpv_coordinateList.add(new Coordinate(rd.nextInt(490), rd.nextInt(490)));
}
//a context to dynamically modify the sort algorithm
mpv_sortContext = new Context();
}
//returns the list with all rectangle
public ObservableList<Coordinate> getField() {
return this.mpv_coordinateList;
}
//sort elements (depending on different algorithms)
public ObservableList<Coordinate> sortElements(String p_sortToApply) {
return mpv_sortContext.launchSort(p_sortToApply,
this.mpv_coordinateList);
}
}
正如模型所说,我创建了一个接口(interface),并让从这个接口(interface)继承的具体策略:
public interface SortStrategy {
ObservableList<Coordinate> sort(ObservableList<Coordinate> p_listToSort);
}
public class EvenSort implements SortStrategy {
@Override
public ObservableList<Coordinate> sort(
ObservableList<Coordinate> p_listToSort) {
ObservableList<Coordinate> oddCoordList = FXCollections
.observableArrayList();
for (Coordinate coord : p_listToSort) {
if (coord.x % 2 == 0) {
oddCoordList.add(coord);
}
}
return oddCoordList;
}
}
public class OddSort implements SortStrategy {
@Override
public ObservableList<Coordinate> sort(
ObservableList<Coordinate> p_listToSort) {
ObservableList<Coordinate> oddCoordList = FXCollections
.observableArrayList();
for (Coordinate coord : p_listToSort) {
if (coord.x % 2 == 1) {
oddCoordList.add(coord);
}
}
return oddCoordList;
}
}
具体类只返回一个列表,其中包含所有具有偶数或奇数 x 坐标的坐标。
然后我创建了一个类上下文:
public class Context {
//private SortStrategy mpv_sortStrategy; //never used
private EvenSort mpv_evenSort = new EvenSort();
private OddSort mpv_oddSort = new OddSort();
private StandardSort mpv_standardSort = new StandardSort();
private HashMap<String, SortStrategy> mpv_HashMapStrategies;
public Context() {
//creation of a dictionary with all possible strategies
mpv_HashMapStrategies = new HashMap<String, SortStrategy>();
mpv_HashMapStrategies.put("Even Sort", mpv_evenSort);
mpv_HashMapStrategies.put("Odd Sort", mpv_oddSort);
mpv_HashMapStrategies.put("Standard Sort", mpv_standardSort);
}
public ObservableList<Coordinate> launchSort(String p_sortToApply, ObservableList<Coordinate> p_listToSort){
return mpv_HashMapStrategies.get(p_sortToApply).sort(p_listToSort);
}
}
通过图形用户界面,用户可以选择他想用来对列表进行排序的策略。用户可以单击按钮来启动排序。通过主类(未显示)完成对 inst_field.mpv_sortContext.sortElements(a_string)
的调用,并将字符串作为描述要使用的策略的参数。然后在 sortElements 中使用该字符串来选择用户想要应用的策略实例。
在我的实现中,一方面是客户端,另一方面是处理策略(上下文、接口(interface)和具体类)的所有代码。如果我想添加一个新策略,我只需要在 Context 类中添加一个新策略的实例,并在 gui 中添加一个新策略的描述,让用户知道它。
我知道在我完成的实现中也不是很好,因为 Context 包含每个可能策略的实例,因此我不需要对接口(interface)的引用,但我发现它比让 Field 更干净并且客户知道这些类。
好吧……我完全错了吗?在“规范”策略模式中我错过了什么吗? “规范”方式是实现策略模式的唯一方式吗?或者有没有更好的方法来实现这种模式,只有应该知道的类才知道策略实例,并且可以轻松添加新策略?
最佳答案
I looked for discussions on this pattern but none answered my question... which is how can I implement the Strategy pattern to let it be clean
您的“策略”不一定像您描述的那样不干净,我认为您可能对客户是谁的想法感到困惑。您的客户正在提供要使用的实现,但这可能是必要的实现细节。例如,java RMI tutorial's ComputeEngine基本上只使用这种模式。 “计算”实现由客户端传递 - 因为只有客户端知道要执行的计算。
然而,更常见的是,该策略用于提供一种方法,使逻辑在某些上下文中可配置,或者允许针对特定用途定制通用上下文。它还具有根据需要向客户端隐藏内部结构的好处。通常要这样做,要使用的策略将在内部配置到上下文中。这可能由以下人员提供:
Class.getResourceAsStream
)。这是您的 Context
的扩展类的 map (即从众所周知的位置加载 map )。这里的一个例子是你可以提供一个“表示要使用的默认实现的策略,但允许提供新的实现作为替代策略——例如 defaultXMLParser对于上面的前两点,您可以考虑使用工厂来推导出正确的策略。这将使实现选择问题保持本地化。
Well... Am I totally wrong? Is there something I missed in the "canonical" strategy pattern. Is the "canonical" way the one and only way to implement the Strategy pattern? or Is there a better way to implement this pattern in a way that only the classes which should know are aware of the strategy instances and in a way that adding a new strategy can be easily done?
我会说你没有错。这实际上取决于使用该策略的目的。如果这是一个内部系统问题,那么一些规则应该驱动选择(在工厂后面)。如果它出于某种原因是可配置的,那么它应该由隐藏在上下文中的配置和管理驱动(管理使用该策略的整体逻辑的类)。但是,如果它取决于用户数据或行为,那么要么数据在内部驱动选择,要么您必须接受客户必须将您的策略传递给您。
另请注意,此模式背后的目标是删除条件逻辑,同时保留替代实现。因此,如果您的策略导致您执行大量条件逻辑,那么您可能需要重新考虑它是否能澄清您的代码。
</warandpeace>
关于Java 策略模式——我可以在 Context 类中委托(delegate)策略实例化吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27232794/
我有一个加载 View 的 View ,需要将 View 推送到主导航 Controller 。 我已经为每个 View 设置了一个委托(delegate),并且基本上使我的调用沿着“链”返回到主导航
我通过 NSURLConnction 从服务器获取数据,并希望从获取的数组中填充表格 View 。数据出现在 NSURLConnection 委托(delegate)方法的日志中,但我意识到 numb
我已经将我用作标题 View 的 View 子类化,它里面有一些按钮委托(delegate),它工作得很好。 但是,我在 viewController 上方展示了一个 modalViewControl
我希望这听起来像是一个显而易见的问题,但是委托(delegate)返回类型是否也必须与其委托(delegate)的方法的返回类型相匹配? EG,像这样: public static void Save
我想使用 Kotlin 委托(delegate),但我不想在委托(delegate)人之外创建委托(delegate)。委托(delegate)的所有示例都如下所示: interface Worker
我有一个问题: - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInf
伙计们。我正在寻求帮助。这似乎是一个非常简单的任务,但我可以解决一整天。我正在尝试使用容器 View 创建侧面菜单。当用户按下“更多”按钮(barButtonItem)时,整个 View 向右滑动并出
我正在努力将 UIWebView 迁移到 WKWebView。我已经更改了所有委托(delegate)方法。我需要 WKWebView 委托(delegate)方法等于下面的 UIWebView 委托
我正在学习 VB.NET 中的委托(delegate),但对委托(delegate)类型感到困惑。在阅读有关委托(delegate)的内容时,我了解到委托(delegate)是一种数据类型,可以引用具
我有一个用 Objetive-C 构建的框架。该框架用于连接蓝牙设备并与之交互。 在演示代码中,Objetive-C 委托(delegate)函数如下所示。演示代码由框架创建者提供。 -(void)b
//NewCharts.h #import @interface NewCharts : UIViewController @property(nonatomic,retain)IBOutlet U
我正在努力了解 async/await 并认为我确实了解有关用法的一些事情。但仍然不太清楚在下面的场景中实际好处是什么。 查看 Task.Run 用法。第一种方法使用普通委托(delegate)并使用
我已经尝试了在我的网站上使用 openID 委托(delegate)的所有可能选项,但没有一个方法对我有用。 我的 HTML 文件的 head 部分有“link rel”标签。 我在 HTML 文件的
如何快速创建一个委托(delegate),即 NSUserNotificationCenterDelegate? 最佳答案 这里有一些关于两个 View Controller 之间委托(delegat
我有一个带有数据源的 NSComboBox,当您单击三角形并通过单击它选择其中一个项目时,它可以完美运行。但是,我还希望它允许用户在框中键入以使用自动完成来选择名称。目前,当用户键入时,我希望选择的项
我在代码中定义了以下类和委托(delegate)(为简洁起见,剪掉了许多其他行)。 Public Delegate Sub TimerCallback(canceled As Boolean) Pub
我使用 ansible 2.1 并且我想使用 delegate_to 向一组主机运行命令。我使用 localhost 作为主机参数,并且我想将“touch”命令委托(delegate)给两个 cls
我想通过重载为我的类实现几个构造函数。据我了解,遵循 DRY 原则的惯用方式是使用一种称为委托(delegate)构造函数的功能。我也看到了关于在任何地方使用引用参数并不惜一切代价避免使用指针的想法,
代表们会导致内存泄漏吗? 我的意思是,例如如果一个类A包含一个ADelegate,并且后者指向BMethod(属于B类),这可以防止GC收集A类或B类吗? 如果是这样,我们如何“释放”代表(设置ADe
委托(delegate)命令和路由命令有什么区别? 我读了一些文章说在 MVVM 上使用委托(delegate)命令而不是路由命令。 那么当我们使用 MVVM 时,Delegate Command 相
我是一名优秀的程序员,十分优秀!