Сначала определение: в простейших терминах вы можете определить шаблон стратегии как указание объекту выполнять работу и делать это, используя ДРУГОЙ объект.
Чтобы пояснить это далее, я собираюсь немного изменить дизайн 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
|
@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); } } |
Единственное различие между этим воплощением и первым заключается в том, что класс стратегии Visa внедряется Spring, когда класс загружается с использованием аннотации @Autowired. Подводя итог, я предполагаю, что это означает, что шаблон стратегии является самой популярной моделью в мире.
* Для целей этого обсуждения я предполагаю, что ShoppingCart может окупить себя, но это правильно или нет, это совершенно новый блог…
Ссылка: шаблон стратегии от нашего партнера по JCG Роджера Хьюза в блоге Captain Debug’s Blog .