设计模式和单一原则笔记

发布于:2025-05-01 ⋅ 阅读:(28) ⋅ 点赞:(0)

单一原则:方法 对象

策略模式:方法实现

// 策略接口(单一职责:定义计算规范)
public interface PriceStrategy {
    boolean match(String type);  // 职责1:判断是否适用该策略
    double calculate(double price); // 职责2:执行计算
}

// 具体策略类(每个类只负责一种计算逻辑)
public class VipStrategy implements PriceStrategy {
    @Override
    public boolean match(String type) {
        return "VIP".equals(type);
    }

    @Override
    public double calculate(double price) {
        return price * 0.8;
    }
}

public class FullReductionStrategy implements PriceStrategy {
    @Override
    public boolean match(String type) {
        return "FULL_REDUCTION".equals(type);
    }

    @Override
    public double calculate(double price) {
        return price > 100 ? price - 20 : price;
    }
}

// 上下文类(单一职责:路由策略)
public class PriceContext {
    private List<PriceStrategy> strategies = new ArrayList<>();

    public PriceContext() {
        strategies.add(new VipStrategy());
        strategies.add(new FullReductionStrategy());
    }

    public double execute(String type, double price) {
        return strategies.stream()
               .filter(s -> s.match(type))
               .findFirst()
               .orElseThrow(() -> new IllegalArgumentException("未知价格策略"))
               .calculate(price);
    }
}

** 使用工厂模式隔离对象创建**

// 创建逻辑单独封装
public class PaymentProcessorFactory {
    public PaymentProcessor create(String type) {
        if ("ALIPAY".equals(type)) return new AlipayProcessor();
        if ("WECHAT".equals(type)) return new WechatProcessor();
        throw new IllegalArgumentException("未知支付类型");
    }
}

// 使用方保持单一职责
public class OrderService {
    private PaymentProcessorFactory factory;
    
    public void pay(Order order, String paymentType) {
        PaymentProcessor processor = factory.create(paymentType);
        processor.process(order.getAmount());
    }
}

通过装饰者模式叠加功能

// 基础接口
public interface DataReader {
    String read();
}

// 基础实现(单一职责:读取数据)
public class FileDataReader implements DataReader {
    public String read() {
        // 读取文件内容...
    }
}

// 装饰器1:增加缓存(单一职责:处理缓存)
public class CachedDataReader implements DataReader {
    private DataReader wrappee;
    private String cache;

    public CachedDataReader(DataReader reader) {
        this.wrappee = reader;
    }

    public String read() {
        if (cache == null) {
            cache = wrappee.read();
        }
        return cache;
    }
}

// 装饰器2:增加解密(单一职责:数据解密)
public class DecryptDataReader implements DataReader {
    private DataReader wrappee;

    public DecryptDataReader(DataReader reader) {
        this.wrappee = reader;
    }

    public String read() {
        String data = wrappee.read();
        return decrypt(data);
    }
}

// 使用组合
DataReader reader = new DecryptDataReader(
                     new CachedDataReader(
                       new FileDataReader()));

1 工厂方法模式(子类创建对象 接口屏蔽细节 支持新增产品)

抽象工厂1接口,具体工厂AB实现接口方法,
服务类 1 factory; if (…) {factory = new FactoryA();} factory调用方法

适用场景:需要创建对象但不确定具体类型时(如多数据源切换、协议适配)。
特点

  • 将对象创建延迟到子类
  • 通过接口屏蔽创建细节
  • 支持横向扩展(新增产品类型)

微服务应用示例:多数据库支持(MySQL/Oracle)

// 抽象工厂
public interface DataSourceFactory {
    DataSource createDataSource();
}

// 具体工厂
public class MySQLDataSourceFactory implements DataSourceFactory {
    @Override
    public DataSource createDataSource() {
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setURL("jdbc:mysql://localhost:3306/db");
        return dataSource;
    }
}

public class OracleDataSourceFactory implements DataSourceFactory {
    @Override
    public DataSource createDataSource() {
        OracleDataSource dataSource = new OracleDataSource();
        dataSource.setURL("jdbc:oracle:thin:@localhost:1521:xe");
        return dataSource;
    }
}

// 使用工厂(通过环境变量切换)
public class DatabaseService {
    private DataSource dataSource;

    public DatabaseService() {
        String dbType = System.getenv("DB_TYPE");
        DataSourceFactory factory;
        if ("oracle".equalsIgnoreCase(dbType)) {
            factory = new OracleDataSourceFactory();
        } else {
            factory = new MySQLDataSourceFactory();
        }
        this.dataSource = factory.createDataSource();
    }
}


2 抽象工厂模式(定义抽象产品和工厂并实现,产品不能不太多)

创建工厂A 抽象产品BC 实现A和BC 选择工厂

1. 模式定义
抽象工厂模式是一种创建型设计模式,它提供一个接口用于创建相关或依赖对象的家族,而无需指定具体类。与工厂方法模式不同,抽象工厂关注的是产品族的创建。

核心思想:客户端代码只与抽象接口交互,完全不知道实际创建的具体产品是什么。

2. 模式结构
角色划分

角色 说明 示例代码
AbstractFactory(抽象工厂) 声明创建产品族的方法 GUIFactory
ConcreteFactory(具体工厂) 实现具体产品的创建 WindowsFactory/MacFactory
AbstractProduct(抽象产品) 定义产品接口 Button/Checkbox
ConcreteProduct(具体产品) 实现具体产品类 WindowsButton/MacCheckbox

UML类图
在这里插入图片描述

3. 代码示例:跨平台UI组件库

场景需求
开发一个支持Windows和Mac风格的UI库,需要创建:

  • 按钮(Button)
  • 复选框(Checkbox)

(1)抽象产品定义

// 抽象产品:按钮
public interface Button {
    void render();
    void onClick();
}

// 抽象产品:复选框
public interface Checkbox {
    void paint();
    boolean isChecked();
}

(2)具体产品实现

// Windows风格组件
public class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染Windows风格按钮");
    }
    
    @Override
    public void onClick() {
        System.out.println("Windows按钮点击事件");
    }
}

public class WindowsCheckbox implements Checkbox {
    @Override
    public void paint() {
        System.out.println("绘制Windows风格复选框");
    }
    
    @Override
    public boolean isChecked() {
        return true;
    }
}

// Mac风格组件
public class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染Mac风格按钮");
    }
    
    @Override
    public void onClick() {
        System.out.println("Mac按钮点击事件");
    }
}

public class MacCheckbox implements Checkbox {
    @Override
    public void paint() {
        System.out.println("绘制Mac风格复选框");
    }
    
    @Override
    public boolean isChecked() {
        return false;
    }
}

(3)抽象工厂定义

public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

(4)具体工厂实现

// Windows工厂
public class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

// Mac工厂
public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

(5)客户端代码

public class Application {
    private Button button;
    private Checkbox checkbox;
    
    public Application(GUIFactory factory) {
        this.button = factory.createButton();
        this.checkbox = factory.createCheckbox();
    }
    
    public void paint() {
        button.render();
        checkbox.paint();
    }
    
    public static void main(String[] args) {
        // 根据配置选择工厂
        GUIFactory factory;
        if (System.getProperty("os.name").contains("Windows")) {
            factory = new WindowsFactory();
        } else {
            factory = new MacFactory();
        }
        
        Application app = new Application(factory);
        app.paint();
    }
}

4. 模式优势

优点

  1. 确保产品兼容性:同一工厂创建的对象属于同一产品族
  2. 客户端与具体实现解耦:只依赖抽象接口
  3. 易于扩展新产品族:新增风格只需增加新工厂类

缺点

  1. 增加新产品类型困难:需要修改所有工厂接口(违反开闭原则)
  2. 类数量膨胀:每增加一个产品族需要新增多个类

5. 经典应用场景

  1. 跨平台UI框架(如Java AWT/Swing)
  2. 数据库访问层(支持多种数据库:MySQL/Oracle)
  3. 游戏开发(不同风格的角色/道具生成)
  4. 主题系统(白天/黑夜模式切换)

6. 模式对比
(1)抽象工厂 vs 工厂方法

维度 抽象工厂 工厂方法
关注点 产品族创建 单一产品创建
复杂度 高(需要管理多个产品等级)
扩展方向 横向扩展(新增产品族) 纵向扩展(新增产品类型)
(2)抽象工厂 vs 建造者模式
  • 抽象工厂:立即返回组成产品族的各个对象
  • 建造者:分步骤构建复杂单一对象

7. Spring框架中的实践

Spring的FactoryBean接口与抽象工厂模式思想相似:

public interface FactoryBean<T> {
    T getObject() throws Exception;  // 相当于createProduct()
    Class<?> getObjectType();
    boolean isSingleton();
}

// 使用示例
@Bean
public FactoryBean<DataSource> dataSource() {
    return new AbstractFactoryBean<DataSource>() {
        @Override
        public Class<?> getObjectType() {
            return DataSource.class;
        }
        
        @Override
        protected DataSource createInstance() {
            // 返回具体数据源实现
            return new HikariDataSource();
        }
    };
}

8. 最佳实践建议

  1. 合理控制产品族规模:避免一个工厂需要创建过多产品
  2. 考虑使用依赖注入(如Spring)来管理工厂实例
  3. 与原型模式结合:当产品创建成本高时,可以用原型减少new操作
  4. 明确产品族边界:不同产品族之间不应有隐含依赖

3 模板(代码少 父类掌握流程 有钩子)


抽象类 静态方法写步骤1234,拆分具体步骤,固定/抽象/钩子都行

经典案例
1. Java 集合框架
- AbstractListaddAll() 方法调用 add()(子类如 ArrayList 实现 add())。
2. Servlet 生命周期
- HttpServletservice() 方法调用 doGet()doPost()
3. Sp ring 框架
- JdbcTemplateexecute() 方法定义数据库操作流程,具体 SQL 由回调接口实现。

public abstract class AbstractClass {
    // 模板方法(final防止子类覆盖算法结构)
    public final void templateMethod() {
        step1();     // 固定步骤
        step2();     // 可变步骤(子类实现)
        if (hookMethod()) {  // 钩子方法(可选扩展点)
            step3();  
        }
    }

    // 固定实现(所有子类共用)
    private void step1() {
        System.out.println("执行固定步骤1");
    }

    // 抽象方法(必须由子类实现)
    protected abstract void step2();

    // 钩子方法(可选覆盖,提供默认实现)
    protected boolean hookMethod() {
        return true;
    }

    // 可选步骤(默认空实现)
    protected void step3() {}



}

优势

  • 代码复用:公共逻辑集中在父类
  • 扩展可控:通过钩子方法提供灵活扩展点
  • 反向控制:父类掌控流程,子类专注实现

劣势

  • 继承强耦合:子类必须依赖父类
  • 违反开闭原则:新增步骤可能需要修改父类
  • 方法爆炸:过多抽象方法会增加子类负担

建议

  1. 模板方法尽量简短(不超过10行)
  2. 命名显式化
    • 模板方法用processXXX()/executeXXX()
    • 步骤方法用doXXX()/performXXX()
  3. 谨慎使用继承:如果变化点过多,考虑改用策略模式
  4. 合理使用钩子方法:避免过度设计,只在真正需要扩展点时使用

4 策略模式 (新增不用改旧代码 支付)

模式优势
优点
开闭原则:新增策略无需修改现有代码
消除条件语句:替代大量的if-else/switch-case
运行时灵活切换:动态改变对象行为
算法复用:不同上下文可共享策略对象

缺点
客户端必须了解所有策略:需要知道不同策略的区别
对象数量增加:每个策略都是一个类
通信开销:策略与上下文可能需要交换数据

经典应用场景
支付系统(如示例)
排序算法(快速排序/归并排序动态切换)
游戏AI(不同难度级别的敌人行为)
物流计算(不同快递公司的运费计算)
Spring资源访问Resource接口的不同实现)


网站公告

今日签到

点亮在社区的每一天
去签到