南大复试 - 设计模式

📅 发布时间:2026/7/13 10:14:06 👁️ 浏览次数:
南大复试 - 设计模式
本文主要介绍南大软院复试中可能考察的几种设计模式。1、工厂模式该模式解决了什么问题 某个对象的创建和使用存在冗余代码可以封装创建逻辑解耦对象的创建和使用。- 引例 - 用户可以分别使用支付宝、微信的进行支付以及退款业务public class OrderService { // 1、该方法依据传入的 payType 选择不同的支付方式假设有支付宝和微信两种业务类型 public void payOrder(String orderId, double amount, String payType) { // ---------- tag ---------- // Payment payment null; if (alipay.equals(payType)) { Alipay alipay new Alipay(); // 假设初始化后需要传入用户 id 和用户密码 alipay.setAppId(alipay_123456); alipay.setPrivateKey(alipay_key_789); payment alipay; } else if (wechat.equals(payType)) { WechatPay wechatPay new WechatPay(); // 假设微信也有自己的初始化入参 wechatPay.setMchId(wechat_mch_001); wechatPay.setApiKey(wechat_key_002); payment wechatPay; } else { throw new RuntimeException(不支持的支付方式); } // ---------- tag ---------- // // 2、实例初始化后开始具体业务逻辑 // ………… // } }假设我们要做一个“支付”或是“退款”的业务有两种支付方式支付宝和微信那么业务调用的地方一般是传入一个 payType 根据不同字段选择支付宝和微信的跳转业务逻辑即注释 1。存在的问题1、初始化实例的过程中即上述两个注释 tag 中间的这段代码对于“支付”和“退款”也有可能有其他的业务业务这里的初始化信息一般是不变的。因此如果我们不使用工厂模式那对于“支付”和“退款”这两个方法上述两个 tag 之间的这段代码我们会在这两个方法中原封不动的写两遍。2、若业务需要增加了“银联”支付方式那么我们要在“支付”“退款”这两个方法中分别增加银联的冗余代码。接下来引入简单工厂模式解决这个问题// 1、将支付和退款定义成接口 public interface Payment { String pay(double amount); String refund(double amount); } // 2、抽出支付宝实现类和微信实现类这两个类分别实现支付和退款的业务接口 public class Alipay implements Payment { private String appId; private String privateKey; // 一些支付宝的初始化入参 public void setAppId(String appId) { this.appId appId; } public void setPrivateKey(String privateKey) { this.privateKey privateKey; } Override public String pay(double amount) { // 支付宝支付业务逻辑 } Override public String refund(double amount) { // 支付宝退款业务逻辑 } } public class WechatPay implements Payment { private String mchId; private String apiKey; public void setMchId(String mchId) { this.mchId mchId; } public void setApiKey(String apiKey) { this.apiKey apiKey; } Override public String pay(double amount) { // 微信支付业务逻辑 } Override public String refund(double amount) { // 微信退款业务逻辑 } } // 3、创建一个工厂类 public class PaymentFactory { public static Payment createPayment(String payType) { // 工厂根据传入的 payType 创建支付实例若有其他支付方式也只需在这里扩展 Payment payment switch (payType) { case alipay - new Alipay(); case wechat - new WechatPay(); default - throw new RuntimeException(不支持的支付方式 payType); }; // 统一初始化配置只要在工厂类中写一次支付、退款以及其他业务模块都能用 if (payment instanceof Alipay alipay) { alipay.setAppId(alipay_123456); alipay.setPrivateKey(alipay_key_789); } else if (payment instanceof WechatPay wechatPay) { wechatPay.setMchId(wechat_mch_001); wechatPay.setApiKey(wechat_key_002); } return payment; } } // 4、在原先的业务代码中使用工厂 public class OrderService { public void payOrder(String orderId, double amount, String payType) { // 实例化工厂 PaymentFactory factory new PaymentFactory() // 这里可以把工厂做成一个单例来使用 // 从工厂中获取对应的已经初始化完成的支付方式 Payment payment factory.createPayment(payType); // 支付、退款业务逻辑 // ………… // } }使用工厂模式后实现同样的功能虽然增加了代码行数但是模块之间耦合性降低了若要修改支付宝的初始化代码或是支付、退款逻辑只需在 Class Alipay 中修改若是要增加一个银联的支付方式只需增加一个 Class UnionPay在里面写它的初始化和支付退款业务逻辑业务调用的地方无需进行改动。扩展 - 工厂方法模式上述简单工厂模式如果需要增加银联支付则需要修改工厂类这违反了开闭原则。简单工厂是单工厂多产品的模式因此为防止工厂类随项目扩展变得臃肿我们可以使用多工厂多产品的结构也即是工厂方法模式。// 工厂接口 public interface PaymentFactory { Payment createPayment(); } // 支付宝工厂 public class AlipayFactory implements PaymentFactory { Override public Payment createPayment() { return new Alipay(); } }新增产品时就只需新增新工厂类和新产品类。对于简单工厂和工厂方法模式虽然工厂方法模式符合开闭原则但是代价是增加了代码复杂度不同的产品都需要一个独特工厂是一个混代码量的方法。。个人认为在实际开发中采用简单工厂写出来的代码更简洁易管理。简而言之工厂模式主要是用于封装对象的创建初始化数据代码。2、策略模式同样的首先思考策略模式是为了解决什么问题工厂模式是封装对象的创建代码而策略模式则是封装某个“过程”策略的代码使得策略若是有变更或是扩展时只需低成本改动便可与原业务兼容。- 引例 - 某电商订单折扣计算规则不使用策略模式时的代码如下// 订单类核心业务算法分支混在一起 public class Order { private String userId; private String userType; private double amount; // 计算折扣后金额if-else 臃肿且难扩展 public double calculatePayAmount() { double payAmount 0.0; if (普通用户.equals(userType)) { payAmount amount; } else if (VIP.equals(userType)) { payAmount amount * 0.9; } else if (超级VIP.equals(userType)) { payAmount amount * 0.8; } else if (节日活动.equals(userType)) { // 新增规则需改这里 payAmount amount * 0.85; } else { throw new IllegalArgumentException(未知用户类型); } return payAmount; } // getter/setter 省略 } // 客户端调用 public class Client { public static void main(String[] args) { Order order new Order(); order.setUserId(1001); order.setUserType(VIP); order.setAmount(1000.0); System.out.println(需支付 order.calculatePayAmount()); // 输出900.0 } }该写法存在以下问题1、新增 “节日活动” 折扣时必须修改calculatePayAmount()方法违反开闭原则。2、如果折扣规则调整比如 VIP 改成 8.8 折需要在if-else里找对应分支修改容易误改其他逻辑。3、折扣算法无法复用比如退款模块也需要计算折扣只能复制代码。接下来使用策略模式对这段代码进行修改// 1、定义策略接口定义所有折扣算法的统一方法 public interface DiscountStrategy { // 计算折扣后金额 double calculate(double amount); } // 2、定义不同策略实现该接口 // 普通用户策略 public class NormalUserStrategy implements DiscountStrategy { Override public double calculate(double amount) { return amount; } } // VIP用户策略9折 public class VipUserStrategy implements DiscountStrategy { Override public double calculate(double amount) { return amount * 0.9; } } // 超级VIP用户策略8折 public class SuperVipUserStrategy implements DiscountStrategy { Override public double calculate(double amount) { return amount * 0.8; } } // 节日活动策略8.5折—— 新增策略只需加类无需改旧代码 public class FestivalStrategy implements DiscountStrategy { Override public double calculate(double amount) { return amount * 0.85; } } // 3、定义上下文该类主要用于持有策略对象封装策略的调用逻辑 public class OrderContext { // 持有策略对象 private DiscountStrategy strategy; // 构造方法传入具体策略 public OrderContext(DiscountStrategy strategy) { this.strategy strategy; } // 对外提供的计算方法 public double calculatePayAmount(double amount) { return strategy.calculate(amount); } // 支持动态切换策略可灵活扩展 public void setStrategy(DiscountStrategy strategy) { this.strategy strategy; } } // 4、修改客户端调用逻辑 public class Client { public static void main(String[] args) { double orderAmount 1000.0; // 选择不同策略 DiscountStrategy vipStrategy new VipUserStrategy(); // context 持有该策略 OrderContext context new OrderContext(vipStrategy); // 使用策略计算金额 System.out.println(VIP用户需支付 context.calculatePayAmount(orderAmount)); // 900.0 // 可自由切换策略只需将其传入上下文 context.setStrategy(new FestivalStrategy()); // 使用节日策略计算金额 System.out.println(节日活动需支付 context.calculatePayAmount(orderAmount)); // 850.0 } }可以看出策略模式核心步骤如下1、定义该策略接口2、定义不同类实现该接口3、定义上下文用于持有策略4、客户端中直接实例化上下文以及需要的策略上下文持有策略后就可以使用该策略