策略模式(学习笔记)
1. 意图
定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化
2. 动机
假设打算为游客们创建一款导游程序。该程序的核心功能是提供美观的地图,以帮助用户在任何城市中快速定位。用户期待的程序新功能是自动路线规划:他们希望输入地址后就能在地图上看到前往目的地的最快路线。程序的首个版本只能规划公路路线。驾车旅行的人们对此非常满意。但很显然,并非所有人都会在度假时开车。因此在下次更新时添加了规划步行路线的功能。此后,又添加了规划公共交通路线的功能。而这只是个开始。不久后,又要为骑行者规划路线。又过了一段时间,又要为游览城市中的所有景点规划路线。尽管从商业角度来看,这款应用非常成功,但其技术部分却让你非常头疼:每次添加新的路线规划算法后,导游应用中主要类的体积就会增加一倍。随着需求的不断增加,你觉得自己没法继续维护这堆代码了
策略模式通过定义一些类来封装不同功能背后的算法,从而避免了一个类不断膨胀以至于难以维护的问题。名为上下文的原始类必须包含一个成员变量来存储对于每种策略的引用。上下文并不执行任务,而是将工作委派给已连接的策略对象。上下文不负责选择符合任务需要的算法——客户端会将所需策略传递给上下文。实际上,上下文并不十分了解策略,它会通过同样的通用接口与所有策略进行交互,而该接口只需暴露一个方法来触发所选策略中封装的算法即可。因此,上下文可独立于具体策略。这样你就可在不修改上下文代码或其他策略的情况下添加新算法或修改已有算法了。在导游应用中,每个路线规划算法都可被抽取到 buildRoute 方法的独立类中。 该方法接收起点和终点作为参数,并返回路线中途点的集合。
3. 适用性
- 许多相关的类仅仅是行为有异。"策略"提供了一种用多个行为中的一个行为来配置一个类的方法
- 需要使用一个算法的不同变体
- 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句
4. 结构
5. 效果
1. 可以在运行时切换对象内的算法
2. 一个替代继承的方法 如果直接生成一个Context类的子类,从而给它以不同的行为。这会将行为硬性编制到Context中,将算法的实现与Context的实现混合起来,从而使Context难以理解、维护和扩展,而且还不能动态的改变算法
3. 消除了一些条件语句
4. Strategy可以提供相同行为的不同实现
5. 客户必须了解不同的Strategy以选择合适的算法
6. 许多现代编程语言支持函数类型功能,允许你在一组匿名函数中实现不同版本的算法。使用这些函数的方式就和使用策略对象时完全相同,无需借助额外的类和接口来保持代码简洁
7. 增加了对象的数目
8. Strategy和Context之间的通信开销 无论各个ConcreteStrategy实现的算法是简单还是复杂,它们都共享Strategy定义的接口。因此很可能某些ConcreteStrategy不会用到所有通过这个接口传递给它们的信息,简单的ConcreteStrategy可能不使用其中的任何信息!这就意味着有时Context会创建和初始化一些永远不会用到的参数。如果存在这个问题,需要在Strategy和Context之间进行更紧密的耦合
6. 代码实现
在本例中,策略模式被用于在电子商务应用中实现各种支付方法。客户选中希望购买的商品后需要选择一种支付方式:Paypal 或者信用卡。具体策略不仅会完成实际的支付工作,还会改变支付表单的行为,并在表单中提供相应的字段来记录支付信息
strategies/PayStrategy.java: 通用的支付方法接口
package strategy.strategies;/** * @author GaoMing * @date 2021/7/26 - 20:57 * Common interface for all strategies. */public interface PayStrategy { boolean pay(int paymentAmount); void collectPaymentDetails();}
strategies/PayByPayPal.java: 使用 PayPal 支付
package strategy.strategies;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Map;/** * @author GaoMing * @date 2021/7/26 - 20:57 */public class PayByPayPal implements PayStrategy{ private static final Map<String, String> DATA_BASE = new HashMap<>(); private final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in)); private String email; private String password; private boolean signedIn; static { DATA_BASE.put("amanda1985", "amanda@ya.com"); DATA_BASE.put("qwerty", "john@amazon.eu"); } /** * Collect customer's data. */ @Override public void collectPaymentDetails() { try { while (!signedIn) { System.out.print("Enter the user's email: "); email = READER.readLine(); System.out.print("Enter the password: "); password = READER.readLine(); if (verify()) { System.out.println("Data verification has been successful."); } else { System.out.println("Wrong email or password!"); } } } catch (IOException ex) { ex.printStackTrace(); } } private boolean verify() { setSignedIn(email.equals(DATA_BASE.get(password))); return signedIn; } /** * Save customer data for future shopping attempts. */ @Override public boolean pay(int paymentAmount) { if (signedIn) { System.out.println("Paying " + paymentAmount + " using PayPal."); return true; } else { return false; } } private void setSignedIn(boolean signedIn) { this.signedIn = signedIn; }}
strategies/PayByCreditCard.java: 使用信用卡支付
package strategy.strategies;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;/** * @author GaoMing * @date 2021/7/26 - 20:58 */public class PayByCreditCard implements PayStrategy{ private final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in)); private CreditCard card; /** * Collect credit card data. */ @Override public void collectPaymentDetails() { try { System.out.print("Enter the card number: "); String number = READER.readLine(); System.out.print("Enter the card expiration date 'mm/yy': "); String date = READER.readLine(); System.out.print("Enter the CVV code: "); String cvv = READER.readLine(); card = new CreditCard(number, date, cvv); // Validate credit card number... } catch (IOException ex) { ex.printStackTrace(); } } /** * After card validation we can charge customer's credit card. */ @Override public boolean pay(int paymentAmount) { if (cardIsPresent()) { System.out.println("Paying " + paymentAmount + " using Credit Card."); card.setAmount(card.getAmount() - paymentAmount); return true; } else { return false; } } private boolean cardIsPresent() { return card != null; }}
strategies/CreditCard.java: 信用卡类
package strategy.strategies;/** * @author GaoMing * @date 2021/7/26 - 20:58 */public class CreditCard { private int amount; private String number; private String date; private String cvv; CreditCard(String number, String date, String cvv) { this.amount = 100_000; this.number = number; this.date = date; this.cvv = cvv; } public void setAmount(int amount) { this.amount = amount; } public int getAmount() { return amount; }}
context/Order.java: 订单类
package strategy.context;import strategy.strategies.PayStrategy;/** * @author GaoMing * @date 2021/7/26 - 20:59 * Order class. Doesn't know the concrete payment method (strategy) user has * picked. It uses common strategy interface to delegate collecting payment data * to strategy object. It can be used to save order to database. * */public class Order { private int totalCost = 0; private boolean isClosed = false; public void processOrder(PayStrategy strategy) { strategy.collectPaymentDetails(); // Here we could collect and store payment data from the strategy. } public void setTotalCost(int cost) { this.totalCost += cost; } public int getTotalCost() { return totalCost; } public boolean isClosed() { return isClosed; } public void setClosed() { isClosed = true; }}
Demo.java: 客户端代码
package strategy;import strategy.context.Order;import strategy.strategies.PayByCreditCard;import strategy.strategies.PayByPayPal;import strategy.strategies.PayStrategy;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Map;/** * @author GaoMing * @date 2021/7/26 - 20:56 */public class Demo { private static Map<Integer, Integer> priceOnProducts = new HashMap<>(); private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); private static Order order = new Order(); private static PayStrategy strategy; static { priceOnProducts.put(1, 2200); priceOnProducts.put(2, 1850); priceOnProducts.put(3, 1100); priceOnProducts.put(4, 890); } public static void main(String[] args) throws IOException { while (!order.isClosed()) { int cost; String continueChoice; do { System.out.print("Please, select a product:" + "\n" + "1 - Mother board" + "\n" + "2 - CPU" + "\n" + "3 - HDD" + "\n" + "4 - Memory" + "\n"); int choice = Integer.parseInt(reader.readLine()); cost = priceOnProducts.get(choice); System.out.print("Count: "); int count = Integer.parseInt(reader.readLine()); order.setTotalCost(cost * count); System.out.print("Do you wish to continue selecting products? Y/N: "); continueChoice = reader.readLine(); } while (continueChoice.equalsIgnoreCase("Y")); if (strategy == null) { System.out.println("Please......原文转载:http://www.shaoqun.com/a/892278.html
跨境电商:https://www.ikjzd.com/
燕文物流:https://www.ikjzd.com/w/2229
香港会计师事务所:https://www.ikjzd.com/w/2434
亚马逊t恤:https://www.ikjzd.com/w/1932
1.意图 定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化 2.动机 假设打算为游客们创建一款导游程序。该程序的核心功能是提供美观的地图,以帮助用户在任何城市中快速定位。用户期待的程序新功能是自动路线规划:他们希望输入地址后就能在地图上看到前往目的地的最快路线。程序的首个版本只能规划公路路线。驾车旅行的人们对此非常满意。但很显然,并非所
四川为全国旅游标准化探路 - :http://www.30bags.com/a/409798.html
四川为什么简称蜀 四川简称蜀的来历:http://www.30bags.com/a/433462.html
四川温泉旅游酒店推荐 :http://www.30bags.com/a/411984.html
四川温泉旅游线路推荐_四川泡温泉哪里好_四川哪里有温泉 :http://www.30bags.com/a/414193.html
被两个黑人玩得站不起来了 女朋友被黑人征服小说:http://lady.shaoqun.com/m/a/247406.html
自述陪读发生了性关系 小东西早想在这办了你了:http://lady.shaoqun.com/m/a/256967.html
口述被房东老头不停的要 被老头玩好爽快受不了:http://lady.shaoqun.com/m/a/247575.html
行长将她双腿分得更开 少妇从反抗到迎合:http://lady.shaoqun.com/m/a/248343.html
大学周边的酒店往往供不应求。他们在里面做什么?你有过难忘的经历吗?:http://lady.shaoqun.com/a/428529.html
女人给你这四个暗示是因为想和你发生关系!:http://lady.shaoqun.com/a/428530.html
2021深圳欢乐谷狂欢节游玩攻略(时间、门票、活动):http://www.30bags.com/a/517596.html
2021深圳世界之窗啤酒节游玩攻略(时间、门票、活动):http://www.30bags.com/a/517597.html
Comments
Post a Comment