策略模式的现实世界例子

111
我一直在阅读有关OCP原则及如何使用策略模式实现此目标的内容。
我想向一些人解释,但我唯一能想到的例子是根据“订单”状态使用不同的验证类。
我已经阅读了一些在线文章,但这些文章通常没有描述使用策略的真正原因,例如生成报告/账单/验证等...
您认为有哪些现实世界的例子中策略模式很常见?
19个回答

3

您确定"订单"的状态不是状态模式吗?我有一种预感,无论订单的状态如何,它都不会被处理得不同。

以Order上的方法Ship为例:

order.Ship();
  • 如果运输方式因其状态而异,则使用策略模式。
  • 如果Ship()方法仅在订单已支付且订单尚未发货时成功,则拥有状态模式。

我找到的最好的状态模式(以及其他模式)的例子是在书籍“Head First Design Patterns”中,这本书非常棒。 一个接近第二的例子将是David Cumps' blogging series of patterns


HeadFirst这本书现在正摊开在我的桌子上。非常好的参考资料。 - greg

2

计算商品GST税总额的示例

public interface TaxCalculation {

    public Double calculateTax(Double price);  
}

public class FivePercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        
        Double dbl = (price*5)/100;
        return dbl;
    }

}

public class EighteenPercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        Double dbl = (price*18)/100;
        return dbl;
    }

}

public class Item {

    public String name;
    public Double price;
    public int taxRate;
    public Double totalTax;
    
    public Item(String name, Double price, int taxRate) {
        super();
        this.name = name;
        this.price = price;
        this.taxRate = taxRate;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
    public int getTaxRate() {
        return taxRate;
    }

    public void setTaxRate(int taxRate) {
        this.taxRate = taxRate;
    }

    public Double getTotalTax() {
        return totalTax;
    }

    public void setTotalTax(Double totalTax) {
        this.totalTax = totalTax;
    }

    public void calculateTax(TaxCalculation taxcalulation, Double price) {
        this.totalTax = taxcalulation.calculateTax(price);
    }
    
    @Override
    public String toString() {
        return "Items [name=" + name + ", price=" + price + ", taxRate=" + taxRate + ", totalTax=" + totalTax + "]";
    }
    
}

public class CalculateTax {

    public static void main(String[] args) {
        
        List<Item> itemList = new ArrayList<>();
        
        Item item1 = new Item("Engine Oil", 320.0, 5);
        Item item2 = new Item("Painting", 3500.00, 18);
        
        itemList.add(item1);
        itemList.add(item2);
        
        itemList.stream().forEach(x-> {
            if(x.getTaxRate() == 5) {
                x.calculateTax(new FivePercentage(), x.getPrice());
            } else if(x.getTaxRate() == 18) {
                x.calculateTax(new EighteenPercentage(), x.getPrice());
            }
        });
        
        itemList.stream().forEach(x-> {
            System.out.println(x.toString());
        });
    }
}

2
在一个相当复杂的引擎中,我使用了策略方法,并且这个应用程序是一个很好的例子。基本上,引擎的作用是首先找到拥有小部件的人员名单,其次是根据未知数量的参数(如价格、距离、以前的业务、库存量、运输选项等等)确定哪些是拥有小部件的10个最佳人员。
我们将问题分成两个策略。第一个是数据检索,因为我们知道我们有多个小部件来源,我们需要能够获取数据并将其转换为通用结构。然后我们意识到,我们有多个算法,一些是基于参数权重,其他的非常奇怪和专有,如果没有展示图表,我们无法准确处理它们,我们有很多用于选择最佳人员的算法。
我们的服务本身非常简单,基本上定义了输入、输出,并对数据进行了一些规范化处理,还使用提供程序模式来插入特定于应用程序的数据提供程序和算法提供程序,这是一个相当有效的系统。我们曾经争论过我们是否在使用策略或模板模式,但我们从未解决该问题。

2
假设您想编写一个算法来计算给定月份和年份的第n个Xday,例如2014年10月的第二个星期一。您想使用Android的Time类android.text.format.Time表示日期,但您还想编写一个通用算法,也适用于java.util.Calendar。

这是我所做的。

在DatetimeMath.java中:

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

在TimeMath.java文件中:

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

在OrdinalDayOfWeekCalculator.java文件中,这个类包含一个通用算法:
public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

在我的Android应用中,我会调用类似以下的内容:
OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

如果我想在java.util.Calendar中重复使用相同的算法,我只需编写一个实现DatetimeMath中三个方法的类CalendarMath,然后使用它即可。

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);

1
我们不得不为一个具有非常复杂数据库的企业平台创建第三方供应接口。要提供数据,我们将我们的数据类型列表作为优先级队列放入我们的应用程序中,以便根据依赖关系按正确顺序写入数据库。
然后编写该数据的过程相当简单,只需不断从优先级队列的顶部弹出并选择基于提取的对象类型的策略即可。

1
几周前,我添加了一个常见的Java接口,由我们的一个领域对象实现。这个领域对象是从数据库加载的,数据库表示是一个带有10多个分支的星型模式。拥有这样一个重量级的领域对象的一个后果是,我们不得不制作其他代表相同模式的领域对象,尽管它们不那么重量级。因此,我让其他轻量级对象实现了相同的接口。换句话说,我们有:
public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

最初,我想使用CollectibleElephant来对Elephant进行排序。很快,我的队友们开始使用CollectibleElephant来运行安全检查、过滤它们在发送到GUI时的内容等。


0
这篇答案是为初学者设计的,旨在以最简单的示例帮助他们理解此概念 -(参考:《Headfirst 设计模式》)
#include<iostream>
using namespace std;

/*
    Where it is applicable?
    The selection of an algorithm is required from a family of algorithms.
    To avoid multiple conditional statements for selection of algorithms
    and to hide its algorithm data structures and complexity from client.
*/

class Fly {
public:
    virtual void fly() = 0;
};

//concrete Fly : rocketFly
class rocketFly : public Fly {
public:
    void fly() {
        cout <<"rocketFly::fly()" << endl;
    }
};

//concrete Fly : normalFly
class normalFly : public Fly {
public:
    void fly() {
        cout <<"normalFly::fly()" << endl;
    }
};

//Duck "HAS A" relationship with Fly
class Duck {
private:
    //Duck has a Fly behavour
    Fly* flyObj;
public:
    Duck(Fly* obj) : flyObj(obj) {
        
    }

    void DuckFly() {
        flyObj->fly();
    }
};

int main() {
    rocketFly* rObj = new rocketFly;
    Duck wildDuck(rObj);
    wildDuck.DuckFly();

    normalFly* nObj = new normalFly;
    Duck cityDuck(nObj);
    cityDuck.DuckFly();

    /*
        I didn't have to create classes like wildDuck which inherits from Duck and they implement their own
        fly, quack etc behaviour. There will be code duplication.
        So, instead of that, create an interface of fly, make concrete fly classes with different
        fly behaviour. Use objects to any of these concrete classes to inject to one generic duck
        class which will automatically call correct fly behaviour.
    */

return 0;
}

0

来自维基百科

在计算机编程中,策略模式(也称为策略模式)是一种行为软件设计模式,它使得在运行时选择算法成为可能。代码不直接实现单个算法,而是接收运行时指令,以使用算法族中的哪一个。

在Windows画图应用程序中,您可以看到策略模式,其中您可以在不同的部分独立选择形状和颜色。这里的形状和颜色是可以在运行时更改的算法。

如果您想要用红色画一个圆形,他们不会提供“RedCircle”选项,而是让您选择圆形和您选择的颜色。

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

没有策略模式,将会增加形状和颜色的笛卡尔积数量的类。此外,每个实现都会改变接口。

0
想象一下一个带有AI敌人的射击游戏。 你希望他们根据发生的情况以不同的方式持续战斗.. 使用策略模式,您可以持续循环并动态更改特定操作或行为的执行方式。
interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接