策略模式的现实示例
我一直在阅读有关 OCP 原则 以及如何使用策略模式来完成此任务。
我打算尝试向几个人解释这一点,但我能想到的唯一例子是根据“订单”的状态使用不同的验证类。
我在网上读过几篇文章,但这些文章通常不会描述使用该策略的真正相似的原因,例如生成报告/账单/验证等...
是否有任何您认为策略的真实示例模式常见吗?
I've been reading about the OCP principle and how to use the strategy pattern to accomplish this.
I was going to try and explain this to a couple of people, but the only example I can think of is using different validation classes based on what status an "order" is.
I've read a couple of articles online, but these don't usually describe a real alike reason to use the strategy, like generating reports/bills/validation, etc...
Are there any real-world examples where you think a strategy pattern is common?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(19)
怎么样:
你必须加密一个文件。
对于小文件,您可以使用“内存中”策略,其中读取整个文件并将其保存在内存中(假设文件<1 GB)对于
大文件,您可以使用另一种策略,其中读取文件的部分内容存储在内存中,部分加密结果存储在 tmp 文件中。
对于同一任务,这可能是两种不同的策略。
客户端代码看起来是一样的:
将
返回密码的正确策略实例。
(我什至不知道 Cipher 是否是正确的词:P)
What about this:
You have to encrypt a file.
For small files, you can use "in memory" strategy, where the complete file is read and kept in memory ( let's say for files < 1 gb )
For large files, you can use another strategy, where parts of the file are read in memory and partial encrypted results are stored in tmp files.
These may be two different strategies for the same task.
The client code would look the same:
The
Would return the correct strategy instance for the cipher.
( I don't even know if Cipher is the right word :P )
同样,这是一篇旧帖子,但仍然出现在搜索中,因此我将添加另外两个示例(代码采用 C# 语言)。 我非常喜欢策略模式,因为当项目经理说:“我们希望应用程序执行‘X’,但‘X’尚不清楚,并且它可能在不久的将来发生变化时,它多次救了我的命。 ”
此解释策略模式的视频以《星际争霸》为例。
属于此类别的东西:
排序:我们想要对这些数字进行排序,但我们不知道是否要使用 BrickSort、BubbleSort 或其他排序
验证:我们需要根据“某些规则”检查项目,但尚不清楚该规则是什么,我们可能会认为 。
游戏:我们希望玩家在移动时能够行走或奔跑,但也许在未来,他还应该能够游泳、飞行、传送、在地下挖洞等。
存储信息:我们希望应用程序将信息存储到数据库,但稍后它可能需要能够保存文件,或进行网络调用
输出:我们需要将 X 输出为纯字符串,但稍后可能是 CSV、XML、JSON 等。
示例
我有一个项目,用户可以将产品分配给数据库中的人员。 将产品分配给某人的状态为“已批准”或“已拒绝”,这取决于某些业务规则。 例如:如果用户将产品分配给某个年龄的人,则该产品的状态应被拒绝; 如果项目中的两个字段之间的差异大于50,则其状态被拒绝等等。
现在,在开发阶段这些业务规则还没有完全清晰,并且随时可能出现新的规则。 策略模式的强大之处在于我创建了一个 RuleAgent,它给出了 IRules 列表。
在将产品分配给某人时,我创建一个 RuleAgent,为其提供一个规则列表(全部实现 IRule),并要求它验证分配。 它将贯穿所有规则。 其中,因为它们都实现相同的接口,所以都具有 IsApproved 方法,并且如果其中任何一个返回 false,则返回 false。
现在,例如,当经理突然出现并说,我们还需要拒绝所有实习生的分配,或所有加班人员的分配......你创建这样的新类:
你会发现你不必继续添加或者删除 if 语句或代码,只需创建一个实现 IRUle 接口的新规则类,并在需要时将其切换出来。
另一个很好的例子:Scott Allen 的视频系列,位于 http://www.asp.net/mvc/pluralsight 他在应用程序的单元测试部分使用策略模式。
他构建了一个网站,其中有一个页面根据受欢迎程度显示项目。 然而,“受欢迎”可以是很多东西(最多的浏览量、最多的订阅者、创建日期、最多的活动、最少的评论量等),并且如果管理层还不知道如何订购,并且可能想要尝试不同的方式稍后订购。 您使用 order 方法创建一个接口(IOrderAlgorithm 或其他东西),并让 Orderer 对象将排序委托给 IOrderAlgorithm 接口的具体实现。 您可以创建“CommentOrderer”、“ActivityOrderer”等...并在出现新需求时将其切换出去。
Again, an old post but still turns up on searches so I'll add two more examples (Code is in C#). I absolutely love the Strategy pattern since it has saved my butt a lot of times when the project managers say: "We want the application to do 'X', but 'X' is not yet clear and it can change in the near future."
This video explaining the strategy pattern, uses StarCraft as an example.
Stuff that falls in this category:
Sorting: We want to sort these numbers, but we don't know if we are gonna use BrickSort, BubbleSort or some other sorting
Validation: We need to check items according to "Some rule", but it's not yet clear what that rule will be, and we may think of new ones.
Games: We want player to either walk or run when he moves, but maybe in the future, he should also be able to swim, fly, teleport, burrow underground, etc.
Storing information: We want the application to store information to the Database, but later it may need to be able to save a file, or make a webcall
Outputting: We need to output X as a plain string, but later may be a CSV, XML, JSON, etc.
Examples
I have a project where the users can assign products to people in a database. This assignment of a product to a person has a status which is either "Approved" or "Declined", which is dependent on some business rules. For example: if a user assigns a product to a person with a certain age, it's status should be declined; If the difference between two fields in the item is larger than 50, it's status is declined, etc.
Now, at the moment of development these business rules are not yet all completely clear, and new rules could come up at any time. The power of the stragety-pattern is that I made a RuleAgent, which is given a list of IRules.
At the moment of assigning a product to a person, I create a RuleAgent, give it a list of rules (which all implement IRule), and ask it to validate an assignment. It'll run through all it's rules. Which, because they all implement the same interface, all have the
IsApproved
method and return false if any of them returns false.Now when for instance the manager suddenly comes up and says, we also need to decline all assignments to interns, or all assignments to people working overtime... You make new classes like this:
You see that you don't have to keep adding or removing if-statements or code, just make a new rule-class that implements the IRUle interface and switch those out when needed.
Another great example: Scott Allen's video series at http://www.asp.net/mvc/pluralsight where he uses the strategy pattern in the Unit-test part of the application
He builds a website which has a page that displays items based on popularity. However "Popular" can be many things (most views, most subscribers, creation date, most activity, least amount of comments, etc), and in case management doesn't yet know exactly how to order, and may want to experiment with different orderings at a later date. You make an interface (IOrderAlgorithm or something) with an order method, and let an Orderer-object delegate the ordering to a concrete implementation of the IOrderAlgorithm interface. You can make a "CommentOrderer", "ActivityOrderer", etc... And just switch these out when new requirements come up.
要点:
策略是行为设计模式。 它用于在算法系列之间进行切换。
一个真实的例子:航空公司在某些月份(7 月至 12 月)提供折扣。 您可以拥有一个票价模块,该模块根据月份数决定定价选项。
看一个简单的例子。 该示例可以扩展到在线零售应用程序,该应用程序可以轻松地在特殊日子/欢乐时光为购物车商品提供折扣。
输出:
Key notes:
Strategy is behavioral design pattern. It is used to switch between family of algorithms.
One real word example : Airlines offering discounts during some months (July-December). You can have one Fare module, which decides pricing options depending on month number.
Have a look at a simple example. This example can be extended to on-line retailing applications, which provides discount to shopping cart items on special days/happy hours easily.
output:
我可以想到几个相当简单的例子:
数据压缩。 您可能有一个 ICompressor 接口,其唯一方法如下所示:
字节[]压缩(字节[]输入);
您的具体压缩类可能是 RunLengthCompression、DeflateCompression 等。
I can think of several fairly simple examples:
Data compression. You might have an ICompressor interface whose sole method looks something like this:
byte[] compress(byte[] input);
Your concrete compression classes might be things like RunLengthCompression, DeflateCompression, etc.
策略模式的一个常见用法是定义自定义排序策略(在没有高阶函数的语言中),例如在 Java 中按长度对字符串列表进行排序,传递一个匿名内部类(策略接口的实现)
:以类似的方式,策略可以用于对象数据库的本机查询,例如在 db4o 中:
One common usage of the strategy pattern is to define custom sorting strategies (in languages without higher-order functions), e.g. to sort a list of strings by length in Java, passing an anonymous inner class (an implementation of the strategy interface):
In a similar manner, strategies can be used for native queries with object databases, e.g. in db4o:
我有一个应用程序,每天将其用户群与我们的企业目录同步。 用户是否符合资格取决于他们在大学的身份。 每天,配置程序都会进行一次,并确保那些应该符合资格的人在应用程序中得到配置,而那些不符合资格的人则被取消配置(实际上是根据优雅的降级算法,但这不是重点)。 周六,我进行了更彻底的更新,同步每个用户的一些属性并确保他们具有适当的资格。 在月底,我会根据当月的使用情况进行一些帐单处理。
我使用可组合策略模式来执行此同步。 主程序基本上根据星期几(仅同步更改/同步所有)和相对于校历的学期时间来选择主策略。 如果计费周期即将结束,那么它还会将其与计费策略组合起来。 然后它通过标准接口运行所选策略。
我不知道这种情况有多常见,但我觉得它非常适合策略模式。
I have an application that synchronizes it's user base each day against our enterprise directory. User's are eligible or not eligible based on their status in the University. Each day the provisioning program goes through and makes sure that those who are supposed to be eligible are provisioned in the application and those who are not are de-provisioned (actually according to a graceful degradation algorithm, but that's beside the point). On Saturday I do a more thorough update that synchronizes some properties of each user as well as making sure that they have the proper eligibility. At the end of the month I do some bill back processing based on usage for that month.
I use a composable strategy pattern to do this synchronization. The main program basically chooses a master strategy depending on the day of the week (sync changes only/sync all) and the time of semester relative to the academic calendar. If the billing cycle is ending, then it also composes it with a billing strategy. It then runs the chosen strategy via a standard interface.
I don't know how common this is, but I felt like it was a perfect fit for the strategy pattern.
策略模式的一个很好的例子是在游戏中,我们可以有不同的角色,每个角色可以有多种武器来攻击,但一次只能使用一种武器。 所以我们有角色作为上下文,例如国王,指挥官,骑士,士兵
武器作为一种策略,其中 Attack() 可以是取决于所使用的武器的方法/算法。 因此,如果具体的武器类是 Sword、Axe、Crossbow、BowAndArrow 等……它们都会实现 Attack() 方法。 我确信不需要进一步的解释。
A good example of strategy pattern would be in a game where we can have different characters and each character can have multiple weapons to attack but at a time can use only one weapon. So we have the character as the context, for example King, Commander, Knight ,Soldier
and weapon as a strategy where attack() could be the method/algorithm which depends on the weapons being used. So if the concrete weapon classes were Sword, Axe, Crossbow, BowAndArrow etc .. they would all implement the attack() method. I am sure further explanation is not needed.
我知道这是一个老问题,但我认为我最近实现了另一个有趣的例子。
这是文档交付系统中使用的策略模式的一个非常实际的示例。
我有一个 PDF 交付系统,它接收包含大量文档和一些元数据的档案。 根据元数据,它决定将文档放在哪里; 比如说,根据数据,我可以将文档存储在
A
、B
或C
存储系统中,或三者的混合中。不同的客户使用该系统,并且在出现错误时有不同的回滚/错误处理要求:一个人希望交付系统在第一个错误时停止,将所有已交付的文档保留在其存储中,但停止该过程并且不交付任何其他内容; 另一位希望在存储到
C
时出现错误时从B
回滚,但保留已交付给A
的内容。 很容易想象第三个或第四个也会有不同的需求。为了解决这个问题,我创建了一个基本的交付类,其中包含交付逻辑,以及从所有存储回滚内容的方法。 在发生错误时,交付系统实际上不会直接调用这些方法。 相反,该类使用依赖注入来接收“回滚/错误处理策略”类(基于使用系统的客户),该类在出现错误时被调用,如果适合该策略,该类又会调用回滚方法。
交付类本身向策略类报告发生的情况(哪些文档被交付到哪些存储,以及发生了哪些故障),并且每当发生错误时,它都会询问策略是否继续。 如果策略说“停止它”,则该类将调用该策略的“cleanUp”方法,该方法使用先前报告的信息来决定从交付类中调用哪些回滚方法,或者干脆不执行任何操作。
因此,我现在有两种不同的策略:一种是 QuitterStrategy(在出现第一个错误时退出并且不清除任何内容),另一种是 MaximizeDeliveryToAStrategy(它会尝试尽可能多的策略)尽可能不中止进程,并且永远不会回滚传送到存储
A
的内容,但如果传送到C
失败,则回滚B
中的内容)。根据我的理解,这是策略模式的一个例子。 如果您(是的,您正在阅读)认为我错了,请在下面发表评论并告诉我。 我很好奇什么构成了策略模式的“纯粹”使用,以及我的实现的哪些方面违反了定义。 我觉得它看起来有点搞笑,因为策略界面有点胖。 到目前为止我看到的所有例子都只使用了一种方法,但我仍然认为这封装了一种算法(如果一段业务逻辑可以被认为是一种算法,我认为它确实如此)。
由于该策略还会在交付执行期间收到有关事件的通知,因此它也可以被视为观察者,但那是另一个故事了。
经过一点研究,这似乎是一种称为 顾问。 它是关于是否应该继续交付的顾问,但它也是一个主动的错误处理程序,因为它可以在需要时回滚内容。
无论如何,这是一个相当复杂的示例,可能会让您感觉策略模式的用法都太简单/愚蠢了。 当与其他模式一起使用时,它可能非常复杂,甚至更适用。
I know this is an old question, but I think I have another interesting example that I implemented recently.
This is a very practical example of the strategy pattern being used in a document delivery system.
I had a PDF delivery system which received an archive containing lots of documents and some metadata. Based on the metadata, it decided where to put the document in; say, depending on the data, I could store the document in
A
,B
, orC
storage systems, or a mix of the three.Different customers used this system, and they had different rollback / error handling requirements in case of errors: one wanted the delivery system to stop on the first error, leave all documents already delivered in their storages, but stop the process and not deliver anything else; another one wanted it to rollback from
B
in case of errors when storing inC
, but leave whatever was already delivered toA
. It's easy to imagine that a third or fourth one will also have different needs.To solve the problem, I have created a basic delivery class that contains the delivery logic, plus methods for rolling back stuff from all storages. Those methods are not actually called by the delivery system directly in case of errors. Instead, the class uses Dependency Injection to receive a "Rollback / Error Handling Strategy" class (based on the customer using the system), which is called in case of errors, which in turn calls the rollback methods if it's appropriate for that strategy.
The delivery class itself reports what's going on to the strategy class (what documents were delivered to what storages, and what failures happened), and whenever an error occurs, it asks the strategy whether to continue or not. If the strategy says "stop it", the class calls the strategy's "cleanUp" method, which uses the information previously reported to decide which rollback methods to call from the delivery class, or simply do nothing.
So I now have two different strategies: one is the
QuitterStrategy
(which quits on the first error and cleans up nothing) and the other one is theMaximizeDeliveryToAStrategy
(which tries as much as possible not to abort the process and never rollback stuff delivered to storageA
, but rollbacks stuff fromB
if delivery toC
fails).From my understanding, this is one example of the strategy pattern. If you (yes, you reading) think I'm wrong, please comment below and let me know. I'm curious as to what would constitute a "pure" use of the strategy pattern, and what aspects of my implementation violate the definition. I think it looks a bit funny because the strategy interface is a bit fat. All examples I've seen so far use only one method, but I still think this encapsulates an algorithm (if a piece of business logic can be considered an algorithm, which I think it does).
Since the strategy is also notified about events during the delivery execution, it can also be considered an Observer, but that's another story.
From doing a little research, it seems like this is a "composite pattern" (like MVC, a pattern that uses multiple design patterns underneath in a particular way) called the Advisor. It's an advisor on whether the delivery should continue or not, but it's also an active error handler since it can rollback stuff when asked to.
Anyways, this is a quite complex example that might make that feeling of yours that usages of the strategy pattern are all too simple / silly. It can be really complex and even more applicable when used together with other patterns.
策略模式是最常用的模式,专门用于验证和排序算法。
让我用一个简单的实际示例来解释
这个测试代码是
相同的示例取自 http://coder2design.com /策略模式/
Strategy pattern is most commonly used pattern specially for validations and sorting algorithms.
Let me explain with a simple practical example
The test code for this is
Same example is taken from http://coder2design.com/strategy-pattern/
您确定“订单”的状态不是状态模式吗? 我有预感,订单不会根据其状态进行不同的处理。
以订单上的运送方法为例:
其状态的函数,那么你就
得到了一个策略模式。
Ship() 方法仅成功
订单付款后,以及
订单尚未发货,
你有一个状态模式。
我发现的状态模式(和其他模式)的最好例子是在书“Head第一个设计模式”,这太神奇了。
紧随其后的是David Cumps 的博客系列模式。
Are you sure that the status of an "order" is not a State pattern? I have a hunch that an order will not be handled differently depending on its status.
Take for example the method Ship on the Order:
function of its status, then you've
got a strategy pattern.
the Ship() method succeeds only
when the order has been paid, and
the order has not been shipped yet,
you've got a state pattern.
The best example of the state pattern (and other patterns) I found was in the book "Head First Design Patterns", which is amazing.
A close second will be David Cumps' blogging series of patterns.
计算商品 GST 税总额的示例
Example to calculate Item GST Tax Total
我在一个应用程序的相当复杂的引擎中使用了策略方法,这是一个很好的例子。 本质上,引擎的作用是首先找到拥有小部件的人员列表,第二个作用是根据未知数量的参数(例如之前业务的价格距离)找出拥有小部件的 10 名最佳人员。 ,库存金额,运输选项等等等...)
本质上我们所做的是将问题分为两种策略,第一个是数据检索,因为我们知道我们的小部件有多个来源,并且我们需要能够获取数据并将其转换为通用结构。
然后我们还意识到,我们有多种算法,其中一些是基于参数加权的,另一些则非常奇怪和适当,如果不拿出 visios 和图表,我就无法公正地对待它们,好吧,你明白了,我们有很多算法选择最优秀的人才。
我们的服务本身本质上定义了输入、输出并对数据进行了一些标准化,它还使用提供者模式来插入使用该策略的应用程序特定数据提供者和算法提供者。 这是一个相当有效的系统。
我们对是否使用策略或模板模式进行了一些争论,但我们从未解决过。
I used the strategy approach in a fairly complex engine in an application that is a good example. Essentially the engine's role was to go and first find a list of people who had a widget, it's second role was to figure out which were the 10 best people with a widget based on an unknown number of parameters (things like price distance previous business together, ammount on stock, shipping options etc etc etc...)
Essentially what we did was we broke the problem into two strategies the first being data retrieval, as we knew that we had multiple sources of our widgets and we needed to be able to get the data and transform it to a common structure.
We then also realized that we had multiple algorithims some were based on weighting the parameters, others were very weird and propitery and I couldn't do them justice without pulling out visios and charts and well you get the picture, we had lots of algorithims for selecting the best people.
Our service itself was very thing it essentially defined the inputs, outputs and did some normalization of the data, it also used a provider pattern to plug-in the application specific data providers and algorithim providers which used the strategy. This was a fairly effective system.
We had some debates if we were using a strategy or a template pattern which we never resolved.
假设您想要编写一个算法来计算给定月份和年份的第 n 个 Xday,例如 2014 年 10 月的第二个星期一。您想要使用 Android 的 Time 类
android.text。 format.Time
来表示日期,但您还想编写一个也适用于java.util.Calendar
的通用算法。这就是我所做的。
在 DatetimeMath.java 中:
在 TimeMath.java 中:
在 OrdinalDayOfWeekCalculator.java 中,具有通用算法的类:
在我的 Android 应用程序中,我会调用类似的内容
如果我想为
java.util.Calendar< 重用相同的算法/code>,我只需编写一个类 CalendarMath 来实现 DatetimeMath 中的三个方法,然后使用
Let's say you want to write an algorithm to calculate the nth Xday of a given month and year, e.g., the second Monday of October 2014. You want to use Android's Time class
android.text.format.Time
to represent the date, but you also want to write a generic algorithm that can also apply tojava.util.Calendar
.This is what I did.
In DatetimeMath.java:
In TimeMath.java:
In OrdinalDayOfWeekCalculator.java, the class with the generic algorithm:
In my Android app, I would call something like
If I want to reuse the same algorithm for
java.util.Calendar
, I would just write a class CalendarMath that implements the three methods in DatetimeMath and then use几周前,我添加了一个通用 Java 接口,该接口由我们的域对象之一实现。 该域对象是从数据库加载的,数据库表示是一个具有大约 10 多个分支的星型模式。 拥有如此重量级的域对象的后果之一是,我们必须创建代表相同模式的其他域对象,尽管重量级较小。 所以我让其他轻量级对象实现相同的接口。 换句话说,我们有:
最初,我想使用
CollectibleElephant
来对Elephant
进行排序。 很快,我的队友就开始使用CollectibleElephant
来运行安全检查,在它们发送到 GUI 时对其进行过滤等。A few weeks ago, I added a common Java interface which was implemented by one of our domain objects. This domain object was loaded from the database, and the database representation was a star schema with about 10+ branches. One of the consequences of having such a heavy weight domain object is that we've had to make other domain objects that represented the same schema, albeit less heavyweight. So I made the other lightweight objects implement the same interface. Put otherwise we had:
Originally, I wanted to use
CollectibleElephant
to sortElephant
s. Pretty quickly, my teammates glommed ontoCollectibleElephant
to run security checks, filter them as they get sent to the GUI, etc.我们必须为具有非常复杂数据库的企业平台创建第三方配置接口。 要配置的数据的提交是作为我们的数据类型的列表,这些数据类型被放入应用程序的优先级队列中,以便由于依赖关系,它们可以以正确的顺序写入数据库。
写入该数据的过程非常简单,不断从优先级队列的顶部弹出,然后根据提取的对象的类型选择策略。
We had to create a third-party provisioning interface for an enterprise platform with a very complicated database. The submission of data to be provisioned was as a list of our data types which were put into a priority queue in our application so they could be written to the database in the correct order due to dependencies.
The process to write that data was then quite simple, keep popping off the top of the priority queue and then choose a strategy based on the type of the object that you extract.
来自维基百科
在 Windows Paint 应用程序中,您可以看到一个策略模式,您可以在其中在不同部分中独立选择形状和颜色。 这里的形状和颜色是可以在运行时改变的算法。
如果您想用红色绘制一个圆圈,他们不会提供“RedCircle”选项,而是让您选择圆圈和您选择的颜色。
如果没有策略模式,形状和颜色的笛卡尔积会增加类的数量。 每个实现的接口也会发生变化。
From wikipedia
In Windows Paint application you can see a strategy pattern where you can choose the shape and color independently in a different sections. Here the shape and color are the algorithms which can changed at runtime.
If you want to draw a circle with red color, rather than providing an option of 'RedCircle' they let you choose the circle and a color of your choice.
Without strategy pattern will increase the number of classes with the Cartesian product of shape and color. Also the interface changes for each implementation.
例如,想象一下有人工智能敌人的射击游戏。
你希望他们根据发生的情况以不同的方式持续战斗..
使用策略模式,您可以连续循环并动态更改特定操作或操作的执行方式。
Imagine a shooter game with AI enemies for example.
You want them to continuously fight in different ways based on what happens ..
With strategy pattern you can continuously loop and dynamically change how a specific or action will be performed.
这个答案是针对初学者并希望通过最简单的示例来理解这一点的人 - (参考:Headfirst Design Patterns)
This answer is for someone who is a beginner and want to understand this with the simplest example possible - (Reference : Headfirst Design Patterns)