如何优雅地将设计模式运用到实际项目中?
🌈 设计模式介绍
所谓 “设计模式”,是一套被反复使用和验证的方法论。从更宏观的角度看,只要能够解决实际问题并符合使用场景,设计模式既可以应用于领域驱动设计(DDD),也可以用于具体的项目开发。
🤔 常用的设计模式有哪些?
- 策略模式(Strategy)
- 工厂模式(Factory)
- 单例模式(Singleton)
- 代理模式(Proxy)
- 工厂方法模式(Factory Method)
- 观察者模式(Observer)
- 模板方法模式(Template Method)
- 适配器模式(Adapter)
设计模式应用示例
以下通过具体的案例,展示设计模式如何优雅地解决实际问题。
3.1 策略模式
示例场景
商场促销活动,根据客户购买金额提供不同折扣策略:
- 金额 ≥ 2000:打八折(0.8)。
- 500 ≤ 金额 < 2000:打九折(0.9)。
- 金额 < 500:打九五折(0.95)。
通过策略模式实现不同折扣策略的逻辑。
实现步骤
- 定义策略接口:
public interface Strategy {
String strategy(); // 返回当前策略唯一标识
void algorithm(); // 策略计算逻辑
}
- 实现策略接口:
public class ConcreteStrategyA implements Strategy {
@Override
public String strategy() {
return StrategySelector.STRATEGY_A.getStrategy();
}
@Override
public void algorithm() {
System.out.println("process with strategyA...");
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public String strategy() {
return StrategySelector.STRATEGY_B.getStrategy();
}
@Override
public void algorithm() {
System.out.println("process with strategyB...");
}
}
- 定义策略枚举:
@Getter
public enum StrategySelector {
STRATEGY_A(1, "strategyA"),
STRATEGY_B(2, "strategyB");
private final Integer code;
private final String strategy;
StrategySelector(Integer code, String strategy) {
this.code = code;
this.strategy = strategy;
}
}
- 创建策略调度器:
public class StrategyRunnerImpl implements StrategyRunner {
private static final Map<String, Strategy> STRATEGY_MAP;
static {
List<Strategy> strategies = List.of(new ConcreteStrategyA(), new ConcreteStrategyB());
STRATEGY_MAP = strategies.stream().collect(Collectors.toMap(Strategy::strategy, s -> s));
}
@Override
public void execute(String strategy) {
STRATEGY_MAP.get(strategy).algorithm();
}
}
- 整合至 Spring 项目:
配置类通过 Spring 容器注入 StrategyRunner
:
@Configuration
public class StrategyConfig {
@Bean
public StrategyRunner runner(List<Strategy> strategies) {
Map<String, Strategy> strategyMap = strategies.stream()
.collect(Collectors.toMap(Strategy::strategy, s -> s));
return strategy -> strategyMap.get(strategy).algorithm();
}
}
- 控制层调用:
@RestController
@RequestMapping("/designPatterns")
public class DesignPatternController {
@Autowired
private StrategyRunner strategyRunner;
@GetMapping("/algorithm")
public void algorithm(@RequestParam("strategy") String strategy) {
strategyRunner.execute(strategy);
}
}
效果:
访问接口后输出:
process with strategyA...
3.2 简单工厂模式
示例场景
实现支付场景:支持支付宝、微信支付,并通过工厂模式封装不同支付逻辑。
- 定义支付接口:
public interface IPayment {
Boolean pay(PaymentBody paymentBody);
}
- 实现支付接口:
public class AliPay implements IPayment {
@Override
public Boolean pay(PaymentBody paymentBody) {
System.out.println("支付宝支付...");
return true;
}
}
public class WechatPay implements IPayment {
@Override
public Boolean pay(PaymentBody paymentBody) {
System.out.println("微信支付...");
return true;
}
}
- 创建支付工厂:
@Component
public class PaymentFactory {
public static IPayment getPayStrategy(String type) {
switch (type) {
case "AliPay": return new AliPay();
case "WechatPay": return new WechatPay();
default: throw new IllegalArgumentException("不支持的支付方式");
}
}
}
- 统一入口处理支付:
@Component
public class PaymentStrategyHandler {
public static Boolean pay(PaymentBody paymentBody) {
IPayment payment = PaymentFactory.getPayStrategy(paymentBody.getType());
return payment.pay(paymentBody);
}
}
- 控制层调用:
@RestController
@RequestMapping("/designPatterns")
public class DesignPatternController {
@PostMapping("/pay")
public Boolean pay(@RequestBody PaymentBody paymentBody) {
return PaymentStrategyHandler.pay(paymentBody);
}
}
3.3 单例模式
实现懒汉式单例模式(静态内部类):
class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
3.4 代理模式
示例场景
中介代理出租房子的案例。
- 定义抽象类:
public interface Subject {
void rentHouse(); // 出租房子接口
}
- 实现具体角色:
public class HouseOwner implements Subject {
@Override
public void rentHouse() {
System.out.println("房东成功出租了房子...");
}
}
- 实现代理角色:
public class HouseProxy implements Subject {
private final HouseOwner houseOwner = new HouseOwner();
@Override
public void rentHouse() {
System.out.println("中介收取代理费...");
houseOwner.rentHouse();
}
}
3.5 工厂方法模式
- 定义工厂接口:
public interface NetworkConfigFactoryService {
NetworkConfigCrudService getSpecificService(String productType);
}
- 实现工厂类:
@Service
public class NetworkConfigFactoryServiceImpl implements NetworkConfigFactoryService {
@Override
public NetworkConfigCrudService getSpecificService(String productType) {
switch (productType) {
case "A": return new AServiceImpl();
case "B": return new BServiceImpl();
default: throw new IllegalArgumentException("未定义的产品类型");
}
}
}
3.6 观察者模式
示例场景
气象站监控气象变化,通知订阅者更新天气数据。
- 定义主题和观察者接口:
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObserver();
}
interface Observer {
void update(float temp, float humidity, float pressure);
}
- 实现主题类:
class WeatherData implements Subject {
private final List<Observer> observers = new ArrayList<>();
private float temperature, humidity, pressure;
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void setMeasurements(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
notifyObserver();
}
}
- 实现观察者类:
class CurrentConditionDisplay implements Observer {
@Override
public void update(float temp, float humidity, float pressure) {
System.out.println("更新天气数据:温度=" + temp + ", 湿度=" + humidity + ", 气压=" + pressure);
}
}
效果:
当气象站数据更新时,所有订阅者自动接收最新数据并更新显示。
设计模式的优雅之处在于抽象设计和灵活扩展。结合场景选择合适的模式,能显著提高代码的可读性和可维护性。
3.7 模板方法模式
模板方法(Template Method)是一种行为设计模式,用于创建方法框架并将某些实现步骤推迟到子类中。
模板方法定义了算法的执行步骤,允许提供可能对所有或部分子类通用的默认实现。通过一个简单的例子理解该模式:假设我们要提供一个建造房子的算法,建造步骤包括:
- 建造地基
- 建造支柱
- 建造墙壁
- 安装窗户
这些步骤的顺序不可更改。例如,在建造地基前不能安装窗户。在这种情况下,可以创建一个模板方法,它定义了执行顺序,而具体实现由子类负责。
核心思想:
- 通用步骤可在父类中实现。
- 子类可覆盖特定步骤的实现。
- 为防止模板方法被子类覆盖,应将其定义为
final
方法。
模板方法抽象类
模板方法模式需要一个抽象基类,定义了步骤的顺序和部分实现。
示例代码:
// 抽象类 HouseTemplate
public abstract class HouseTemplate {
/**
* 模板方法,定义了执行步骤的顺序
*/
public final void buildHouse() {
buildFoundation(); // 建造地基
buildPillars(); // 建造支柱
buildWalls(); // 建造墙壁
buildWindows(); // 安装窗户
System.out.println("House is built successfully");
}
// 通用实现:建造地基
private void buildFoundation() {
System.out.println("Building foundation with cement, iron rods and sand");
}
// 抽象方法:由子类实现
public abstract void buildPillars();
public abstract void buildWalls();
// 默认实现:安装窗户
private void buildWindows() {
System.out.println("Building Glass Windows");
}
}
子类实现
木屋:
public class WoodenHouse extends HouseTemplate {
@Override
public void buildPillars() {
System.out.println("Building Pillars With Wood coating...");
}
@Override
public void buildWalls() {
System.out.println("Building Wooden Walls...");
}
}
玻璃房:
public class GlassHouse extends HouseTemplate {
@Override
public void buildPillars() {
System.out.println("Building Pillars With Glass coating...");
}
@Override
public void buildWalls() {
System.out.println("Building Glass Walls...");
}
}
混凝土房:
public class ConcreteHouse extends HouseTemplate {
@Override
public void buildPillars() {
System.out.println("Building Pillars With Concrete coating...");
}
@Override
public void buildWalls() {
System.out.println("Building Concrete Walls...");
}
}
客户端调用
public class HousingClient {
public static void main(String[] args) {
HouseTemplate houseBuilder;
houseBuilder = new WoodenHouse();
houseBuilder.buildHouse();
System.out.println("--------------");
houseBuilder = new GlassHouse();
houseBuilder.buildHouse();
System.out.println("--------------");
houseBuilder = new ConcreteHouse();
houseBuilder.buildHouse();
}
}
输出结果:
Building foundation with cement, iron rods and sand
Building Pillars With Wood coating...
Building Wooden Walls...
Building Glass Windows
House is built successfully
--------------
Building foundation with cement, iron rods and sand
Building Pillars With Glass coating...
Building Glass Walls...
Building Glass Windows
House is built successfully
--------------
Building foundation with cement, iron rods and sand
Building Pillars With Concrete coating...
Building Concrete Walls...
Building Glass Windows
House is built successfully
3.8 适配器模式
适配器模式(Adapter)用于将一个接口转换成另一个客户所期望的接口,使原本不兼容的类能够一起工作。
角色分析
- 目标接口(Target):客户期待的接口。
- 需要适配的对象(Source/Adaptee):需要适配的原始类。
- 适配器(Adapter):通过包装适配对象,实现目标接口。
示例:网线适配器
假设我们有一根网线(Adaptee),需要通过 USB 接口(Target)连接到电脑。我们创建一个适配器来完成这个转换。
网线(Adaptee):
public class Adaptee {
public void request() {
System.out.println("连接网线上网");
}
}
目标接口(Target):
public interface NetToUsb {
void handleRequest();
}
适配器(Adapter):
public class Adapter extends Adaptee implements NetToUsb {
@Override
public void handleRequest() {
super.request();
}
}
客户端调用:
public class Computer {
public void net(NetToUsb adapter) {
adapter.handleRequest();
}
public static void main(String[] args) {
Computer computer = new Computer();
Adapter adapter = new Adapter();
computer.net(adapter);
}
}
输出结果:
连接网线上网
四、总结
设计模式(Design Patterns)代表最佳实践,是资深开发人员应掌握的重要技能。它们是针对常见问题的解决方案,由大量经验总结而成。
本期内容到此结束,希望对您有所帮助!
评论区