问题描述
我一直在阅读有关 OCP原则以及如何使用策略模式为此做到这一点.
我要尝试向几个人解释这一点,但是我能想到的唯一例子是基于"订单"的状态是不同的验证类.
我已经在线阅读了几篇文章,但是这些文章通常并不描述使用该策略的真正理由,例如生成报告/账单/验证等...
有没有现实世界中的示例,您认为策略模式很普遍?
推荐答案
呢:
您必须加密文件.
对于小文件,您可以使用"内存"策略,其中读取完整的文件并保存在内存中(例如,对于文件<1 GB)
对于大文件,您可以使用另一种策略,其中文件的部分记在内存,部分加密结果存储在TMP文件中.
这可能是同一任务的两种不同的策略.
客户端代码看起来相同:
File file = getFile(); Cipher c = CipherFactory.getCipher( file.size() ); c.performAction(); // implementations: interface Cipher { public void performAction(); } class InMemoryCipherStrategy implements Cipher { public void performAction() { // load in byte[] .... } } class SwaptToDiskCipher implements Cipher { public void performAction() { // swapt partial results to file. } }
Cipher c = CipherFactory.getCipher( file.size() );
将返回密码的正确策略实例.
我希望这会有所帮助.
(我什至不知道密码是否正确:p)
其他推荐答案
再次,一个旧的帖子,但仍在搜索上,因此我将添加两个示例(代码在C#中).我绝对喜欢这种策略模式,因为它已经为我的屁股节省了很多次,当时项目经理说:"我们希望应用程序执行'x',但是'x'尚不清楚,并且在不久的将来可能会改变. " 此视频解释了策略模式以示例为例.
.属于此类别的东西:
-
排序:我们想对这些数字进行排序,但是我们不知道我们是否要使用Bricksort,Bubblesort或其他分类
-
验证:我们需要根据"某些规则"检查项目,但尚不清楚该规则是什么,我们可能会想到新规则.
-
游戏:我们希望玩家在移动时走路或跑步,但也许将来,他还应该能够游泳,飞翔,传送,地下洞穴等>
-
存储信息:我们希望该应用程序将信息存储到数据库中,但是后来它可能需要保存文件或制作WebCall
-
输出:我们需要输出X作为平字符串,但后来可能是CSV,XML,JSON等.
示例
我有一个项目,用户可以在该项目中将产品分配给数据库中的人.将产品分配给一个人的状态是"批准"或"拒绝"的,这取决于某些业务规则.例如:如果用户将产品分配给具有一定年龄的人,则应拒绝其状态;如果项目中两个字段之间的差异大于50,则其状态被拒绝,等等.
.现在,在开发时期,这些业务规则尚未完全清楚,并且新规则可能随时出现.浪漫故事的力量是我制作了一个规则,得到了irules的清单.
public interface IRule { bool IsApproved(Assignment assignment); }
在将产品分配给人的那一刻,我创建了一个规则,列出了一系列规则(所有这些都实现了irule),并要求它验证作业.它将贯穿所有规则.由于它们都实现了相同的界面,因此所有界面都具有IsApproved方法,如果其中任何一个返回false,则返回false.
现在,例如,当经理突然出现并说,我们还需要拒绝对实习生的所有作业,或者对工作人员的所有任务...您进行了这样的新课程:
public OvertimeRule : IRule { public bool IsApproved(Assignment assignment) //Interface method { if (assignment.Person.Timesheet >= 40) { return false; } return true; } } public InternRule : IRule { public bool IsApproved(Assignment assignment) //Interface method { if (assignment.Person.Title == "Intern") { return false; } return true; } }
您看到您不必继续添加或删除IF-Statement或代码,只需制作一个新的规则类,以实现IRULE接口并在需要时切换它们.
另一个很好的例子:斯科特·艾伦(Scott Allen)的视频系列,网址为 他在应用程序的单位测试部分中使用策略模式
他构建了一个网站,该网站的页面根据受欢迎程度显示项目.但是,"流行"可能是很多事情(大多数视图,大多数订户,创建日期,大多数活动,评论数量最少等),并且如果管理层尚不知道如何确切订购,并且可能想尝试不同的以后的订购.您可以使用订单方法制作接口(iorderalgorithm或其他东西),然后让订购器对象将订购委派给Iorderalgorithm接口的具体实现.您可以制作"评论者"," ActivityDorderer"等...然后在新要求出现时将其切换出来.
其他推荐答案
关键说明:
-
策略 是行为设计模式.它用于在算法家族之间切换.
-
此模式包含一个抽象策略接口和该接口的许多 Concrete 策略实现(算法).
-
该应用程序仅使用策略接口.根据某些配置参数,混凝土策略将标记为接口.
uml图,来自 wikipedia
一个真实词的示例:航空公司在几个月(7月至12月)提供折扣.您可以拥有一个票价模块,该模块可以根据月号决定定价选项.
请看一个简单的示例.此示例可以扩展到在线零售应用程序,该应用程序可在特殊的日子/欢乐时光上为购物车的商品提供折扣.
import java.util.*; /* Interface for Strategy */ interface OfferStrategy { public String getName(); public double getDiscountPercentage(); } /* Concrete implementation of base Strategy */ class NoDiscountStrategy implements OfferStrategy{ public String getName(){ return this.getClass().getName(); } public double getDiscountPercentage(){ return 0; } } /* Concrete implementation of base Strategy */ class QuarterDiscountStrategy implements OfferStrategy{ public String getName(){ return this.getClass().getName(); } public double getDiscountPercentage(){ return 0.25; } } /* Context is optional. But if it is present, it acts as single point of contact for client. Multiple uses of Context 1. It can populate data to execute an operation of strategy 2. It can take independent decision on Strategy creation. 3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals 4. Code re-factoring will become easy */ class StrategyContext { double price; // price for some item or air ticket etc. Map<String,OfferStrategy> strategyContext = new HashMap<String,OfferStrategy>(); StrategyContext(double price){ this.price= price; strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy()); strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy()); } public void applyStrategy(OfferStrategy strategy){ /* Currently applyStrategy has simple implementation. You can use Context for populating some more information, which is required to call a particular operation */ System.out.println("Price before offer :"+price); double finalPrice = price - (price*strategy.getDiscountPercentage()); System.out.println("Price after offer:"+finalPrice); } public OfferStrategy getStrategy(int monthNo){ /* In absence of this Context method, client has to import relevant concrete Strategies everywhere. Context acts as single point of contact for the Client to get relevant Strategy */ if ( monthNo < 6 ) { return strategyContext.get(NoDiscountStrategy.class.getName()); }else{ return strategyContext.get(QuarterDiscountStrategy.class.getName()); } } } public class StrategyDemo{ public static void main(String args[]){ StrategyContext context = new StrategyContext(100); System.out.println("Enter month number between 1 and 12"); int month = Integer.parseInt(args[0]); System.out.println("Month ="+month); OfferStrategy strategy = context.getStrategy(month); context.applyStrategy(strategy); } }
输出:
Enter month number between 1 and 12 Month =1 Price before offer :100.0 Price after offer:100.0 Enter month number between 1 and 12 Month =7 Price before offer :100.0 Price after offer:75.0
有用的文章:
策略 dzone的模式
策略 sourcemaking的模式
问题描述
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?
推荐答案
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:
File file = getFile(); Cipher c = CipherFactory.getCipher( file.size() ); c.performAction(); // implementations: interface Cipher { public void performAction(); } class InMemoryCipherStrategy implements Cipher { public void performAction() { // load in byte[] .... } } class SwaptToDiskCipher implements Cipher { public void performAction() { // swapt partial results to file. } }
The
Cipher c = CipherFactory.getCipher( file.size() );
Would return the correct strategy instance for the cipher.
I hope this helps.
( I don't even know if Cipher is the right word :P )
其他推荐答案
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.
public interface IRule { bool IsApproved(Assignment assignment); }
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:
public OvertimeRule : IRule { public bool IsApproved(Assignment assignment) //Interface method { if (assignment.Person.Timesheet >= 40) { return false; } return true; } } public InternRule : IRule { public bool IsApproved(Assignment assignment) //Interface method { if (assignment.Person.Title == "Intern") { return false; } return true; } }
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.
其他推荐答案
Key notes:
Strategy is behavioral design pattern. It is used to switch between family of algorithms.
This pattern contains one abstract strategy interface and many concrete strategy implementations (algorithms) of that interface.
The application uses strategy interface only. Depending on some configuration parameter, the concrete strategy will be tagged to interface.
UML Diagram from wikipedia
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.
import java.util.*; /* Interface for Strategy */ interface OfferStrategy { public String getName(); public double getDiscountPercentage(); } /* Concrete implementation of base Strategy */ class NoDiscountStrategy implements OfferStrategy{ public String getName(){ return this.getClass().getName(); } public double getDiscountPercentage(){ return 0; } } /* Concrete implementation of base Strategy */ class QuarterDiscountStrategy implements OfferStrategy{ public String getName(){ return this.getClass().getName(); } public double getDiscountPercentage(){ return 0.25; } } /* Context is optional. But if it is present, it acts as single point of contact for client. Multiple uses of Context 1. It can populate data to execute an operation of strategy 2. It can take independent decision on Strategy creation. 3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals 4. Code re-factoring will become easy */ class StrategyContext { double price; // price for some item or air ticket etc. Map<String,OfferStrategy> strategyContext = new HashMap<String,OfferStrategy>(); StrategyContext(double price){ this.price= price; strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy()); strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy()); } public void applyStrategy(OfferStrategy strategy){ /* Currently applyStrategy has simple implementation. You can use Context for populating some more information, which is required to call a particular operation */ System.out.println("Price before offer :"+price); double finalPrice = price - (price*strategy.getDiscountPercentage()); System.out.println("Price after offer:"+finalPrice); } public OfferStrategy getStrategy(int monthNo){ /* In absence of this Context method, client has to import relevant concrete Strategies everywhere. Context acts as single point of contact for the Client to get relevant Strategy */ if ( monthNo < 6 ) { return strategyContext.get(NoDiscountStrategy.class.getName()); }else{ return strategyContext.get(QuarterDiscountStrategy.class.getName()); } } } public class StrategyDemo{ public static void main(String args[]){ StrategyContext context = new StrategyContext(100); System.out.println("Enter month number between 1 and 12"); int month = Integer.parseInt(args[0]); System.out.println("Month ="+month); OfferStrategy strategy = context.getStrategy(month); context.applyStrategy(strategy); } }
output:
Enter month number between 1 and 12 Month =1 Price before offer :100.0 Price after offer:100.0 Enter month number between 1 and 12 Month =7 Price before offer :100.0 Price after offer:75.0
Useful articles:
strategy pattern by dzone
strategy pattern by sourcemaking