如何在SRP与DRY原则间平衡多数据源认证逻辑?
解决方案:抽象接口+依赖注入
你这种情况用抽象接口+依赖注入的方案最适合,能完美平衡DRY和SRP原则,具体实现思路如下:
1. 抽象数据源接口
先定义一个统一的数据源接口,把与数据源交互的逻辑封装起来,让认证逻辑与具体数据源解耦:
interface AuthDataSource { // 定义认证所需的数据源操作,比如根据登录DTO获取用户认证数据 UserAuthData getAuthData(LoginDto dto); }
2. 实现具体数据源类
为每个用户实体对应的数据源编写独立的实现类,每个类只负责自身数据源的连接与数据查询:
class DataSourceA implements AuthDataSource { UserAuthData getAuthData(LoginDto dto) { // 连接数据源A、查询认证数据的专属逻辑 } } class DataSourceB implements AuthDataSource { UserAuthData getAuthData(LoginDto dto) { // 连接数据源B、查询认证数据的专属逻辑 } } class DataSourceC implements AuthDataSource { UserAuthData getAuthData(LoginDto dto) { // 连接数据源C、查询认证数据的专属逻辑 } }
3. 创建通用认证基类
将核心的认证逻辑集中在这个基类中,通过构造函数注入AuthDataSource接口。基类只专注于通用认证流程,不关心具体使用哪个数据源:
class BaseAuth { private final AuthDataSource dataSource; // 构造注入数据源 BaseAuth(AuthDataSource dataSource) { this.dataSource = dataSource; } void loginFunction(LoginDto dto) { // 通用认证逻辑:参数校验、调用数据源获取数据、密码校验、生成令牌等 UserAuthData authData = dataSource.getAuthData(dto); // 后续统一的认证步骤... } }
4. 绑定具体认证与数据源(可选)
如果需要为每个用户实体提供单独的认证类标识,只需继承BaseAuth并传入对应数据源即可,无需重复编写登录逻辑:
class AuthA extends BaseAuth { AuthA() { super(new DataSourceA()); } } class AuthB extends BaseAuth { AuthB() { super(new DataSourceB()); } } class AuthC extends BaseAuth { AuthC() { super(new DataSourceC()); } }
方案优势
- 符合DRY原则:通用认证逻辑仅实现一次,所有认证场景复用该逻辑
- 符合SRP原则:
BaseAuth只负责认证流程,每个DataSource只负责对应数据源的操作,职责单一 - 扩展性强:新增用户实体时,只需添加新的
AuthDataSource实现类,无需修改原有认证逻辑
内容的提问来源于stack exchange,提问作者Thet Bhone Htut
相关产品推荐
相关产品推荐

