我想向一些人解释,但我唯一能想到的例子是根据“订单”状态使用不同的验证类。
我已经阅读了一些在线文章,但这些文章通常没有描述使用策略的真正原因,例如生成报告/账单/验证等...
您认为有哪些现实世界的例子中策略模式很常见?
这是怎么样的:
您需要加密一个文件。
对于小文件,您可以使用“内存中”策略,其中完整文件被读取并保存在内存中(假设文件大小小于1 GB)
对于大文件,您可以使用另一种策略,在内存中读取文件的部分并将部分加密结果存储在临时文件中。
这些可能是同一个任务的两种不同策略。
客户端代码看起来相同:
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() );
将为密码返回正确的策略实例。
(我甚至不知道Cipher是否是正确的单词:P)
虽然这是一个老帖子,但仍然会出现在搜索结果中,因此我将添加两个更多的示例(代码使用C#编写)。 我非常喜欢策略模式,因为它在项目经理说:“我们想要应用程序执行'X',但'X'尚不清楚,而且可能会在不久的将来发生变化”时,已经多次拯救了我的后路。
这个视频解释策略模式,以星际争霸为例。
属于此类别的东西:
排序:我们想要对这些数字进行排序,但不知道是否会使用BrickSort、BubbleSort或其他排序方法。
验证:我们需要根据“某个规则”检查项目,但该规则还不清楚,而且我们可能会想到新的规则。
游戏:我们希望玩家在移动时可以步行或奔跑,但也许在未来,他还应该能够游泳、飞行、传送、掘地等。
存储信息:我们希望应用程序将信息存储到数据库中,但以后可能需要能够保存文件或进行Web调用。
输出:我们需要将X作为纯字符串输出,但以后可能是CSV、XML、JSON等。
示例
我有一个项目,用户可以将产品分配给数据库中的人员。 分配产品给人员具有“批准”或“拒绝”的状态,这取决于某些业务规则。 例如:如果用户将产品分配给某个年龄段的人,则其状态应该被拒绝; 如果项目中两个字段之间的差异大于50,则其状态为被拒绝等等。
现在,在开发时,这些业务规则并不都完全清楚,并且随时可能出现新规则。策略模式的威力在于,我制作了一个RuleAgent,它被给予一个IRules列表。
public interface IRule {
bool IsApproved(Assignment assignment);
}
在分配产品给某个人的那一刻,我会创建一个RuleAgent,给它提供一系列规则(这些规则都实现了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语句或代码,只需要创建一个实现IRule接口的新规则类,并在需要时切换即可。
另一个很好的例子是Scott Allen在http://www.asp.net/mvc/pluralsight上的视频系列,在应用程序的Unit-test部分使用了策略模式。
他构建了一个网站,其中有个页面根据流行度显示物品。然而,“流行度”可能有很多含义(最多观看次数、最多订阅者、创建日期、最活跃等等),并且如果管理人员还不确定如何排序,可能会在以后尝试不同的排序方式。你可以创建一个接口(IOrderAlgorithm或类似的名称)和一个Orderer对象,将排序委托给IOrderAlgorithm接口的具体实现。你可以创建一个“CommentOrderer”、“ActivityOrderer”等等......在有新需求时只需切换这些对象。
InternRule
,但是我们如何触发OvertimeRule
?我们如何确保现在调用OvertimeRule.IsApproved
的任何逻辑也会调用InternRule.IsApproved
? - Spencer Ruporttrue
,则该任务分配将被批准。这可以尽可能复杂,例如为某种类型的任务分配应用特定规则(而不是全部规则)。 - Gerardo Cauich关键要点:
策略是一种行为设计模式。它用于在算法族之间进行切换。
一个真实的例子是:航空公司在某些月份(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 , which is optional can be single interface for client. */
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
策略模式的一种常见用途是定义自定义排序策略(在没有高阶函数的语言中),例如在Java中按长度对字符串列表进行排序,通过传递一个匿名内部类(实现策略接口):
List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);
同样地,可以使用策略来处理对象数据库中的本地查询,例如在db4o中:
List<Document> set = db.query(new Predicate<Document>() {
public boolean match(Document candidate) {
return candidate.getSource().contains(source);
}
});
rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);
if (rollbackStrategy.mustAbort()) {
rollbackStrategy.rollback(); // rollback whatever is needed based on reports
return false;
}
QuitterStrategy
(遇到第一个错误就退出,不清理任何东西),另一种是MaximizeDeliveryToAStrategy
(尽可能地不中止进程并且从不回滚存储器A中交付的内容,但如果交付给C失败,则回滚B中的内容)。策略模式是最常用的模式,特别适用于验证和排序算法。
让我用一个简单的实际例子来解释一下。
enum Speed {
SLOW, MEDIUM, FAST;
}
class Sorter {
public void sort(int[] input, Speed speed) {
SortStrategy strategy = null;
switch (speed) {
case SLOW:
strategy = new SlowBubbleSortStrategy();
break;
case MEDIUM:
strategy = new MediumInsertationSortStrategy();
break;
case FAST:
strategy = new FastQuickSortStrategy();
break;
default:
strategy = new MediumInsertationSortStrategy();
}
strategy.sort(input);
}
}
interface SortStrategy {
public void sort(int[] input);
}
class SlowBubbleSortStrategy implements SortStrategy {
public void sort(int[] input) {
for (int i = 0; i < input.length; i++) {
for (int j = i + 1; j < input.length; j++) {
if (input[i] > input[j]) {
int tmp = input[i];
input[i] = input[j];
input[j] = tmp;
}
}
}
System.out.println("Slow sorting is done and the result is :");
for (int i : input) {
System.out.print(i + ",");
}
}
}
class MediumInsertationSortStrategy implements SortStrategy {
public void sort(int[] input) {
for (int i = 0; i < input.length - 1; i++) {
int k = i + 1;
int nxtVal = input[k];
while (input[k - 1] > nxtVal) {
input[k] = input[k - 1];
k--;
if (k == 0)
break;
}
input[k] = nxtVal;
}
System.out.println("Medium sorting is done and the result is :");
for (int i : input) {
System.out.print(i + ",");
}
}
}
class FastQuickSortStrategy implements SortStrategy {
public void sort(int[] input) {
sort(input, 0, input.length-1);
System.out.println("Fast sorting is done and the result is :");
for (int i : input) {
System.out.print(i + ",");
}
}
private void sort(int[] input, int startIndx, int endIndx) {
int endIndexOrig = endIndx;
int startIndexOrig = startIndx;
if( startIndx >= endIndx)
return;
int pavitVal = input[endIndx];
while (startIndx <= endIndx) {
while (input[startIndx] < pavitVal)
startIndx++;
while (input[endIndx] > pavitVal)
endIndx--;
if( startIndx <= endIndx){
int tmp = input[startIndx];
input[startIndx] = input[endIndx];
input[endIndx] = tmp;
startIndx++;
endIndx--;
}
}
sort(input, startIndexOrig, endIndx);
sort(input, startIndx, endIndexOrig);
}
}
这里是对应的测试代码:
public class StrategyPattern {
public static void main(String[] args) {
Sorter sorter = new Sorter();
int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
System.out.print("Input is : ");
for (int i : input) {
System.out.print(i + ",");
}
System.out.println();
sorter.sort(input, Speed.SLOW);
}
}
该网站介绍了策略模式的应用,它是一种常见的软件设计模式,主要用于在运行时根据不同的情况选择不同的算法或行为。通过使用策略模式,我们可以避免大量的if-else语句,并使代码更加清晰和易于维护。public class StrategyDemo {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
Item item1 = new Item("1234", 10);
Item item2 = new Item("5678", 40);
cart.addItem(item1);
cart.addItem(item2);
// pay by paypal
cart.pay(new PaypalStrategy("myemail@example.com", "mypwd"));
// pay by credit card
cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
}
}
interface PaymentStrategy {
public void pay(int amount);
}
class CreditCardStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
this.name = nm;
this.cardNumber = ccNum;
this.cvv = cvv;
this.dateOfExpiry = expiryDate;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid with credit/debit card");
}
}
class PaypalStrategy implements PaymentStrategy {
private String emailId;
private String password;
public PaypalStrategy(String email, String pwd) {
this.emailId = email;
this.password = pwd;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid using Paypal.");
}
}
class Item {
private String upcCode;
private int price;
public Item(String upc, int cost) {
this.upcCode = upc;
this.price = cost;
}
public String getUpcCode() {
return upcCode;
}
public int getPrice() {
return price;
}
}
class ShoppingCart {
// List of items
List<Item> items;
public ShoppingCart() {
this.items = new ArrayList<Item>();
}
public void addItem(Item item) {
this.items.add(item);
}
public void removeItem(Item item) {
this.items.remove(item);
}
public int calculateTotal() {
int sum = 0;
for (Item item : items) {
sum += item.getPrice();
}
return sum;
}
public void pay(PaymentStrategy paymentMethod) {
int amount = calculateTotal();
paymentMethod.pay(amount);
}
}
Cipher C = null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c = SwaptToDiskCipher(); }
- Abhijit MazumderCipherFactory
是一个很好的示例,但可能会让不熟悉策略模式的人感到困惑。 - user487772