- 在VisualStudio中部署GDAL库的C++版本(包括SQLite、PROJ等依赖)
- Android开机流程介绍
- STM32CubeMX教程31USB_DEVICE-HID外设_模拟键盘或鼠标
- 深入浅出Java多线程(五):线程间通信
设计模式是通用的、可复用的代码设计方案,也可以说是针对某类问题的解决方案,因此,掌握好设计模式,可以帮助我们编写更健壮的代码.
wiki中将设计模式分为四类,分别是:
策略模式和状态模式属于其中的行为模式,行为模式——从名称上就可以看出——与动作、操作有关.
这两种模式我接触下来,感觉存在一定的相似性。状态模式中通常会存在一个内部状态,状态改变时行为也会发生改变,而策略模式是针对不同条件下的行为进行封装。总的来说,两者都是在不同条件下有不同的行为。接下来我们分别来看一下.
首先看策略模式,根据针对它的概述,貌似就是一系列算法的封装.
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. 。
当然策略模式不止关于算法的定义,还有对算法的调用。关于这一点我们在策略模式对应的wiki:Strategy pattern页面也能看到相应的描述.
Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use. 。
这句话的大概意思是:代码在运行时接收指令,决定使用一系列算法中的哪一种。在这里一种算法就是对应一个策略.
这个描述很容易让人联想到代码中常见的条件语句if-elseif-else,在条件分支根据不同的指令执行不同的操作。但是很显然,既然是一系列的算法,那就说明可能会有很多、甚至是大量的条件,那么可想而知,如果我们直接使用if-else语句来编写执行代码的话,这部分代码会非常长,并且这会破坏软件设计原则中的单一功能原则,这段代码除了判断条件,还要根据不同的条件执行不同的细节操作.
策略模式中的“策略”,其实指的就是算法。然后条件判断作为一个入口,去调用对应的“策略”。所以我们看到wiki中有下面这段描述:
Typically, the strategy pattern stores a reference to some code in a data structure and retrieves it. This can be achieved by mechanisms such as the native function pointer, the first-class function, classes or class instances in object-oriented programming languages, or accessing the language implementation's internal storage of code via reflection. 。
这段话的意思是:策略模式会在数据结构中存储对某些代码的引用,并对其进行检索。这可以通过本地函数指针、一级函数、面向对象编程语言中的类或类实例,或通过反射 访问 语言实现的代码内部存储等机制来实现.
简单来理解,就是把一系列相关操作封装成函数,一个函数就对应一个算法的实现.
我们知道在软件设计原则中有一条是:对扩展开放,对修改封闭。策略模式与开闭原则是一致的.
According to the strategy pattern, the behaviors of a class should not be inherited. Instead, they should be encapsulated using interfaces. 。
根据策略模式,类的行为不应被继承,它们应使用接口进行封装。也就是说,我们最好不要对父类本身做修改,而是使用接口对子类的行为进行扩展。在wiki中使用了Java来举例子,在JavaScript中也可以做类似的处理,比如不把对应的策略函数加在对象自身,而是统一放在一个地方进行调用,也就是上面所说的在数据结构中存储对某些代码的引用。比如下面这个例子:
某商场中的商品在不同阶段的价格满足固定的逻辑,做了以下封装:
const priceProcessor = {
pre(originPrice) {
if (originPrice >= 100) {
return originPrice - 20;
}
return originPrice * 0.9;
},
onSale(originPrice) {
if(originPrice >= 100) {
return originPrice - 30;
}
return originPrice * 0.8;
},
back(originPrice) {
if(originPrice >= 200) {
return originPrice - 50;
}
return originPrice;
},
fresh(originPrice) {
return originPrice * 0.5;
},
};
pre、onSale、back、fresh分别代表了在预热、大促、返场、尝鲜四种阶段下的价格处理.
在上述代码中,我们在priceProcessor这个数据结构中存储了针对不同阶段下对价格的处理逻辑,也就是各种封装的函数。我们可以调用这些引用,从而实现在不同条件下执行不同的算法.
这样,当我们策划新的促销活动时,只需要在priceProcessor这个结构中增加新的处理逻辑,而不需要影响商品对象和其他的处理逻辑,并且这样子处理后,测试流程中就只需要测试新的处理逻辑,而不需要回归测试整体功能.
每个处理逻辑有单独的函数实现,这也方便不同条件下的算法替换,比如在某次商场大促,想要使用返场的价格,就可以直接调用priceProcessor.back方法,而不需要编写重复冗余的代码.
策略模式的核心很简单,就是单一功能的函数封装。接下来我们继续看状态模式.
The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. 。
状态模式也很简单,就是允许对象在内部状态发生变化时改变其行为.
状态模式的“状态”,就是指对象内部的状态,也就是说,这个模式针对的是存在内部状态的对象.
The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern's interface. 。
我们可以看到wiki这部分也有说,状态模式可以解释为一种策略模式。其实上也就是说,根据不同的状态切换策略;在策略模式下,是根据不同的条件切换不同策略,这个是广泛意义下的条件,而状态模式中,不同条件就特定为不同的内部状态.
这样处理后,就不需要使用条件语句了,可以直接通过不同状态映射不同的行为.
在状态模式的wiki页面中,也列举了它所解决的主要问题:
The state pattern is set to solve two main problems:[4] 。
- An object should change its behavior when its internal state changes.
- State-specific behavior should be defined independently. That is, adding new states should not affect the behavior of existing states.
在某类场景中,第一,对象应根据其内部状态的改变来改变其行为.
第二,特定于状态的行为应独立定义。也就是说,添加新状态不应影响现有状态的行为.
这里看第二点,其实和策略模式的场景很类似.
对应这两个问题,状态模式描述了以下解决方案:
In this, the pattern describes two solutions
- Define separate (state) objects that encapsulate state-specific behavior for each state. That is, define an interface (state) for performing state-specific behavior, and define classes that implement the interface for each state.
- A class delegates state-specific behavior to its current state object instead of implementing state-specific behavior directly.
第一,是定义独立的状态对象,为每个状态封装特定于状态的行为.
第二,类将特定于状态的行为委托给其当前的状态对象,而不是直接实现特定于状态的行为.
因此,状态模式中的关键就在于对状态对象的实现。比如下面这个例子:
一个养生壶有不同的功能,当切换不同的功能时我们可以认为它处于不同的工作状态.
class HealthPot {
constructor() {
this.state = new State();
}
changeState(status) {
this.state.status = status;
// 若状态不存在,则返回
if(!this.state.statusToProcessor[status]) {
return;
}
this.state.statusToProcessor[status]();
}
}
class State {
constructor() {
this.status = '';
}
statusToProcessor = {
water() {
console.log('煮开水');
},
flowersTea() {
console.log('煮花草茶');
},
fruitsTea() {
console.log('煮水果茶');
},
keepWarm() {
console.log('保温');
}
}
}
const hp = new HealthPot();
hp.changeState('flowersTea');
在上述代码中,如何实现特定状态的行为与养生壶本身无关,只与状态对象有关。养生壶的行为只是改变状态,并调用对应方法,这样如果后续有新的状态增加,也不用去修改养生壶这个具体的对象,相当于一种拆分行为.
这其实就有点类似于vue中的状态管理工具vuex.
策略模式和状态模式两者存在一定的相似性,但是策略模式封装的函数其独立性会更高,而状态模式中封装的函数依赖于主体的状态,具体操作代码也可能依赖主体的其他属性,比如养生壶例子中,执行各种功能时,需要保证壶中有水,并且要判断是否通电中等等.
简单来说就是一种拆分、封装的行为,满足软件设计原则中的单一职责和开闭原则.
一般在应用开发初期,由于功能简单,开发者可能不会特别在意拆分,并且通常而言不太提倡提前优化,所以会在之后的维护和迭代中,应用这些模式来优化和重构代码;但是有时设计良好的代码,会更便于代码的维护.
最后此篇关于设计模式:策略模式/状态模式的文章就讲到这里了,如果你想了解更多关于设计模式:策略模式/状态模式的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在通读 Windows Phone 7.5 Unleashed,有很多代码看起来像这样(在页面的代码隐藏中): bool loaded; protected override void OnNav
在cgi服务器中,我这样返回 print ('Status: 201 Created') print ('Content-Type: text/html') print ('Location: htt
我正在查看 esh(easy shell)的实现,无法理解在这种情况下什么是 22 和 9 信号。理想情况下,有一个更具描述性的常量,但我找不到列表。 最佳答案 信号列表及其编号(包括您看到的这两个)
我的Oozie Hive Action 永远处于运行模式。 oozie.log文件中没有显示错误。
我正在编写一个使用 RFCOMM 通过蓝牙连接到设备的 Android 应用程序。我使用 BluetoothChat 示例作为建立连接的基础,大部分时间一切正常。 但是,有时由于出现套接字已打开的消息
我有一个云调度程序作业,它应该每小时访问我的 API 以更新一些价格。这些作业大约需要 80 秒才能运行。 这是它的作用: POST https://www.example.com/api/jobs/
我正在 Tomcat 上访问一个简单的 JSP 页面: 但是当我使用 curl 测试此页面时,我得到了 200 响应代码而不是预期的 202: $ curl -i "http://localhos
有时 JAR-RS 客户端会发送错误的语法请求正文。服务器应响应 HTTP status 400 (Bad Request) , 但它以 HTTP status 500 (Internal Serve
我正在尝试通过 response.send() 发送一个整数,但我不断收到此错误 express deprecated res.send(status): Use res.sendStatus(sta
我已经用 Excel 和 Java 做过很多次了……这次我需要用 Stata 来做,因为保存变量更方便'labels .如何将 dataset_1 重组为下面的 dataset_2? 我需要转换以下
我正在创建一个应用程序,其中的对象具有状态查找功能。为了提供一些上下文,让我们使用以下示例。 帮助台应用程序,其中创建作业并通过以下工作流程移动: 新 - 工作已创建但未分配 进行中 - 分配给工作人
我想在 Keras 中运行 LSTM 并获得输出和状态。在 TF 中有这样的事情 with tf.variable_scope("RNN"): for time_step in range
有谁知道 Scala-GWT 的当前状态 项目? 那里的主要作者 Grzegorz Kossakowski 似乎退出了这个项目,在 Spring 中从事 scalac 的工作。 但是,在 interv
我正在尝试编写一个 super 简单的 applescript 来启动 OneDrive App , 或确保打开,当机器的电源设置为插入时,将退出,或确保关闭,当电源设置为电池时。 我无法找到如何访问
目前我正在做这样的事情 link.on('click', function () { if (link.attr('href') !== $route.current.originalPath
是否可以仅通过查看用户代理来检测浏览器上是否启用/禁用 Javascript。 如果是,我应该寻找什么。如果否,检测用户浏览器是否启用/禁用 JavaScript 的最佳方法是什么 最佳答案 不,没有
Spring 和 OSGi 目前的开发状况如何? 最近好像有点安静了。 文档的最新版本 ( http://docs.spring.io/osgi/ ) 来自 2009 年。 我看到一些声明 Sprin
我正在从主函数为此类创建一个线程,但即使使用 Thread.currentThread().interrupt() 中断它,输出仍然包含“Still Here”行。 public class Writ
为了满足并发要求,我想知道如何在 Godog 中的多个步骤之间传递参数或状态。 func FeatureContext(s *godog.Suite) { // This step is ca
我有一个UIButton子类,它不使用UIImage背景,仅使用背景色。我注意到的一件事是,当您设置按钮的背景图像时,有一个默认的突出显示状态,当按下按钮时,该按钮会稍微变暗。 这是我当前的代码。
我是一名优秀的程序员,十分优秀!