策略模式

在最近的博客上,我收到了Wojciech Soczy?ski的评论,内容涉及在使用“不要问”(TDA)时如何使用“战略”模式实施单一责任原则(SRP)。 在某些时候,我打算进一步讨论这个问题,但首先想到的,这将是一个好主意,用我的购物例子,我用了几个星期前在我的定义策略模式泰尔不问及其后续行动拆卸泰尔不要问博客:

首先定义:用最简单的术语,您可以将策略模式定义为告诉对象执行某项工作并使用ANOTHER对象来完成该工作。

为了进一步阐明这一点,我将通过给它一个pay()*方法来稍微重新设计ShoppingCart:

public class ShoppingCart {

  private final List<Item> items;

  public ShoppingCart() {
    items = new ArrayList<Item>();
  }

  public void addItem(Item item) {

    items.add(item);
  }

  public double calcTotalCost() {

    double total = 0.0;
    for (Item item : items) {
      total += item.getPrice();
    }

    return total;
  }

  public boolean pay(PaymentMethod method) {

    double totalCost = calcTotalCost();
    return method.pay(totalCost);
  }
}

关于pay()方法要注意的是,它采用了类型PaymentMethod的一个参数–在我上面的定义中,PaymentMethod是“另一个”对象。

下一步是将PaymentMethod定义为接口。 为什么要使用界面? 这是因为该技术的强大之处在于您可以在运行时决定将哪种具体类型传递给ShoppingCart进行付款。 例如,给定“付款”界面:

public interface PaymentMethod {

  public boolean pay(double amount);

}

然后,您可以定义任何具体的付款对象,例如Visa或MasterCard,例如:

public class Visa implements PaymentMethod {

  private final String name;
  private final String cardNumber;
  private final Date expires;

  public Visa(String name, String cardNumber, Date expires) {
    super();
    this.name = name;
    this.cardNumber = cardNumber;
    this.expires = expires;
  }

  @Override
  public boolean pay(double amount) {

    // Open Comms to Visa
    // Verify connection
    // Paybill using these details
    return true; // if payment goes through
  }

}

…和

public class MasterCard implements PaymentMethod {

  private final String name;
  private final String cardNumber;
  private final Date expires;

  public MasterCard(String name, String cardNumber, Date expires) {
    super();
    this.name = name;
    this.cardNumber = cardNumber;
    this.expires = expires;
  }

  @Override
  public boolean pay(double amount) {

    // Open Comms to Mastercard
    // Verify connection
    // Paybill using these details
    return true; // if payment goes through
  }

}

最后要做的就是通过单元测试来证明这一点:payBillUsingVisa

@Test
  public void payBillUsingVisa() {

    ShoppingCart instance = new ShoppingCart();

    Item a = new Item("gloves", 23.43);
    instance.addItem(a);

    Item b = new Item("hat", 10.99);
    instance.addItem(b);

    Date expiryDate = getCardExpireyDate();
    PaymentMethod visa = new Visa("CaptainDebug", "1234234534564567", expiryDate);

    boolean result = instance.pay(visa);
    assertTrue(result);

  }

  private Date getCardExpireyDate() {
    Calendar cal = Calendar.getInstance();
    cal.clear();
    cal.set(2015, Calendar.JANUARY, 21);
    return cal.getTime();
  }

在上面的代码中,您可以看到我正在创建一个ShoppingCart,然后添加了一些商品。 最后,我以Visa对象的形式创建了一个新的PaymentMethod,并将其注入到pay(PaymentMethod method)函数中,这是问题的症结所在。 在另一种情况下,我可以轻松创建一个MasterCard对象并将其用作Visa的直接替代品-即作为参数传递的对象是在运行时确定的。

这就定义了战略模式,但这还不是博客的结尾。 如果您曾经使用过Spring,但从未听说过Strategy模式,那么所有这些都应该有点熟悉。 这是因为事实证明,Spring的家伙使用策略模式来支撑他们的整个技术。 如果以上面的示例为例,并进行一些细微更改,我可以得出:

@Component
public class SpringShoppingCart {

  private final List<Item> items;

  @Autowired
  @Qualifier("Visa")
  private PaymentMethod method;

  public SpringShoppingCart() {
    items = new ArrayList<Item>();
  }

  public void addItem(Item item) {

    items.add(item);
  }

  public double calcTotalCost() {

    double total = 0.0;
    for (Item item : items) {
      total += item.getPrice();
    }

    return total;
  }

  public boolean pay() {

    double totalCost = calcTotalCost();
    return method.pay(totalCost);
  }
}

此化身与第一个化身之间的唯一区别是,使用@Autowired注释加载策略类Visa时,Spring会注入该策略类。 综上所述,我猜想这意味着策略模式是世界上最受欢迎的模式。

*出于讨论的目的,我假设ShoppingCart可以自己付费,但是这是否正确,是一个全新的博客……

参考: Captain Debug的Blog博客中的JCG合作伙伴 Roger Hughes的《策略模式》


翻译自: https://www.javacodegeeks.com/2012/04/strategy-pattern.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值