单一原则:方法 对象
策略模式:方法实现
// 策略接口(单一职责:定义计算规范)
public interface PriceStrategy {boolean match(String type); // 职责1:判断是否适用该策略double calculate(double price); // 职责2:执行计算
}// 具体策略类(每个类只负责一种计算逻辑)
public class VipStrategy implements PriceStrategy {@Overridepublic boolean match(String type) {return "VIP".equals(type);}@Overridepublic double calculate(double price) {return price * 0.8;}
}public class FullReductionStrategy implements PriceStrategy {@Overridepublic boolean match(String type) {return "FULL_REDUCTION".equals(type);}@Overridepublic 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 {@Overridepublic DataSource createDataSource() {MysqlDataSource dataSource = new MysqlDataSource();dataSource.setURL("jdbc:mysql://localhost:3306/db");return dataSource;}
}public class OracleDataSourceFactory implements DataSourceFactory {@Overridepublic 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 {@Overridepublic void render() {System.out.println("渲染Windows风格按钮");}@Overridepublic void onClick() {System.out.println("Windows按钮点击事件");}
}public class WindowsCheckbox implements Checkbox {@Overridepublic void paint() {System.out.println("绘制Windows风格复选框");}@Overridepublic boolean isChecked() {return true;}
}// Mac风格组件
public class MacButton implements Button {@Overridepublic void render() {System.out.println("渲染Mac风格按钮");}@Overridepublic void onClick() {System.out.println("Mac按钮点击事件");}
}public class MacCheckbox implements Checkbox {@Overridepublic void paint() {System.out.println("绘制Mac风格复选框");}@Overridepublic boolean isChecked() {return false;}
}
(3)抽象工厂定义
public interface GUIFactory {Button createButton();Checkbox createCheckbox();
}
(4)具体工厂实现
// Windows工厂
public class WindowsFactory implements GUIFactory {@Overridepublic Button createButton() {return new WindowsButton();}@Overridepublic Checkbox createCheckbox() {return new WindowsCheckbox();}
}// Mac工厂
public class MacFactory implements GUIFactory {@Overridepublic Button createButton() {return new MacButton();}@Overridepublic 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. 模式优势
优点:
- 确保产品兼容性:同一工厂创建的对象属于同一产品族
- 客户端与具体实现解耦:只依赖抽象接口
- 易于扩展新产品族:新增风格只需增加新工厂类
缺点:
- 增加新产品类型困难:需要修改所有工厂接口(违反开闭原则)
- 类数量膨胀:每增加一个产品族需要新增多个类
5. 经典应用场景
- 跨平台UI框架(如Java AWT/Swing)
- 数据库访问层(支持多种数据库:MySQL/Oracle)
- 游戏开发(不同风格的角色/道具生成)
- 主题系统(白天/黑夜模式切换)
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>() {@Overridepublic Class<?> getObjectType() {return DataSource.class;}@Overrideprotected DataSource createInstance() {// 返回具体数据源实现return new HikariDataSource();}};
}
8. 最佳实践建议
- 合理控制产品族规模:避免一个工厂需要创建过多产品
- 考虑使用依赖注入(如Spring)来管理工厂实例
- 与原型模式结合:当产品创建成本高时,可以用原型减少new操作
- 明确产品族边界:不同产品族之间不应有隐含依赖
3 模板(代码少 父类掌握流程 有钩子)
、
抽象类 静态方法写步骤1234,拆分具体步骤,固定/抽象/钩子都行
经典案例
1. Java 集合框架
- AbstractList
的 addAll()
方法调用 add()
(子类如 ArrayList
实现 add()
)。
2. Servlet 生命周期
- HttpServlet
的 service()
方法调用 doGet()
或 doPost()
。
3. Sp ring 框架
- JdbcTemplate
的 execute()
方法定义数据库操作流程,具体 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() {}}
优势:
- 代码复用:公共逻辑集中在父类
- 扩展可控:通过钩子方法提供灵活扩展点
- 反向控制:父类掌控流程,子类专注实现
劣势:
- 继承强耦合:子类必须依赖父类
- 违反开闭原则:新增步骤可能需要修改父类
- 方法爆炸:过多抽象方法会增加子类负担
建议
- 模板方法尽量简短(不超过10行)
- 命名显式化:
- 模板方法用
processXXX()
/executeXXX()
- 步骤方法用
doXXX()
/performXXX()
- 模板方法用
- 谨慎使用继承:如果变化点过多,考虑改用策略模式
- 合理使用钩子方法:避免过度设计,只在真正需要扩展点时使用
4 策略模式 (新增不用改旧代码 支付)
模式优势
优点:
开闭原则:新增策略无需修改现有代码
消除条件语句:替代大量的if-else/switch-case
运行时灵活切换:动态改变对象行为
算法复用:不同上下文可共享策略对象
缺点:
客户端必须了解所有策略:需要知道不同策略的区别
对象数量增加:每个策略都是一个类
通信开销:策略与上下文可能需要交换数据
经典应用场景
支付系统(如示例)
排序算法(快速排序/归并排序动态切换)
游戏AI(不同难度级别的敌人行为)
物流计算(不同快递公司的运费计算)
Spring资源访问(Resource
接口的不同实现)