Сначала определение: в простейших терминах вы можете определить шаблон стратегии как указание объекту выполнять работу и делать это, используя ДРУГОЙ объект.
Чтобы пояснить это далее, я собираюсь немного изменить дизайн ShoppingCart, предоставив ему метод pay () *:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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 для совершения платежа. Например, учитывая интерфейс оплаты:
|
1
2
3
4
5
|
public interface PaymentMethod { public boolean pay(double amount);} |
Затем вы можете определить любой конкретный платежный объект, такой как Visa или MasterCard, например:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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 }} |
…и
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@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, а затем добавляю несколько элементов. Наконец, я создаю новый PaymentMethod в форме объекта Visa и внедряю его в функцию pay (метод PaymentMethod), которая является сутью вопроса. В другой ситуации я мог бы легко создать объект MasterCard и использовать его в качестве прямой замены для Visa, то есть объект, который передается в качестве аргумента, определяется во время выполнения.
И это определяет образец Стратегии, но это не конец блога. Если вы когда-либо использовали Spring, но никогда не слышали о шаблоне Strategy, все это должно показаться вам немного знакомым. Это потому, что оказывается, что ребята в Spring используют паттерн стратегии, чтобы поддержать всю свою технологию. Если я возьму свой пример выше и внесу несколько небольших изменений, я могу придумать:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
@Componentpublic 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); }} |
Единственное различие между этим воплощением и первым заключается в том, что класс стратегии Visa внедряется Spring, когда класс загружается с использованием аннотации @Autowired. Подводя итог, я предполагаю, что это означает, что шаблон стратегии является самой популярной моделью в мире.
* Для целей этого обсуждения я предполагаю, что ShoppingCart может окупить себя, но это правильно или нет, это совершенно новый блог…
Ссылка: шаблон стратегии от нашего партнера по JCG Роджера Хьюза в блоге Captain Debug’s Blog .
