当前位置: 首页 > article >正文

设计模式原则,请针对具体代码说明

设计原则总结结合支付模块代码的具体说明一、六大设计原则概览原则英文核心含义开闭原则Open-Closed Principle对扩展开放对修改关闭里氏替换Liskov Substitution子类型必须能替换父类型接口隔离Interface Segregation接口应该小而专一单一职责Single Responsibility一个类只有一个变化原因依赖倒置Dependency Inversion依赖抽象不依赖具体迪米特法则Law of Demeter最少知识原则二、开闭原则OCP定义对扩展开放对修改关闭。新增功能时不应修改现有代码。代码体现java// ❌ 错误做法每次新增支付渠道都要修改这个类 public class BadPayService { public PrePayResult pay(String payType, PayBizParam param) { if (WECHAT.equals(payType)) { return wechatPay(param); } else if (ALIPAY.equals(payType)) { return alipayPay(param); } else if (SIMULATE.equals(payType)) { return simulatePay(param); } // 新增渠道 → 需要修改这个方法 → 违反开闭原则 } } // ✅ 正确做法通过策略模式 工厂模式 Component public class PayHandlerFactory { private final MapPayTypes, PayHandler handlerMap; public PayHandlerFactory(ListPayHandler handlers) { // Spring 自动注入所有 PayHandler 实现类 this.handlerMap handlers.stream() .collect(Collectors.toMap(PayHandler::payTypes, Function.identity())); } public PayHandler getHandler(PayTypes payType) { return handlerMap.get(payType); } } // 新增支付渠道只需添加新类无需修改任何现有代码 Component public class NewPayHandler extends AbstractPayHandler { Override public PayTypes payTypes() { return PayTypes.NEW_PAY; // 新渠道 } Override public PrePayResult doPrePay(PrePayParam param) { // 新渠道的实现 } }原则体现新增支付渠道时只新增NewPayHandler类PayHandlerFactory、PayService、AbstractPayHandler等现有代码一行都不用改。三、里氏替换原则LSP定义子类可以扩展父类的功能但不能改变父类原有的功能。任何使用父类的地方都可以透明地替换为子类。代码体现java// 抽象父类 public abstract class AbstractPayHandler implements PayHandler { public PrePayParam buildPrePayParam(PayTypes payType, PayBizParam payBizParam) { PrePayParam param new PrePayParam(); param.setTradeNo(buildTradeNo(TRADE)); param.setAmount(payBizParam.getAmount()); return param; } protected String buildTradeNo(String codeType) { return redisSerialGenerator.generateIncrNo(codeType); } } // 子类1微信支付 - 保持父类行为契约 public class WechatPayHandler extends AbstractPayHandler { Override public PrePayParam buildPrePayParam(PayTypes payType, PayBizParam payBizParam) { // 调用父类方法保证基础行为不变 PrePayParam param super.buildPrePayParam(payType, payBizParam); // 扩展添加微信特有字段不破坏原有功能 param.setOpenId(payBizParam.getOpenId()); return param; } } // 子类2模拟支付 - 也保持父类行为契约 public class SimulatePayHandler extends AbstractPayHandler { Override public PrePayParam buildPrePayParam(PayTypes payType, PayBizParam payBizParam) { PrePayParam param super.buildPrePayParam(payType, payBizParam); param.setNotifyUrl(buildNotifyUrl()); // 扩展不破坏 return param; } } // 使用方任何子类都可以替换父类位置 Service public class PayService { private PayHandlerFactory factory; public PrePayResult pay(PayTypes payType, PayBizParam param) { PayHandler handler factory.getHandler(payType); // 无论 handler 是 WechatPayHandler 还是 SimulatePayHandler // 都能正常工作 → 里氏替换原则 PrePayParam prePayParam handler.buildPrePayParam(payType, param); return handler.doPrePay(prePayParam); } }原则体现PayService只依赖PayHandler接口不需要知道具体是哪个子类。所有子类都能正确替换父类位置。四、接口隔离原则ISP定义客户端不应该被迫依赖它不使用的方法。接口应该小而专一。代码体现java// ❌ 错误做法大而全的接口 public interface BadPayHandler { PayTypes payTypes(); PrePayResult doPrePay(PrePayParam param); PrePayResult doPrePayWithCoupon(PrePayParam param, Coupon coupon); // 不一定需要 PrePayResult doPrePayWithPoints(PrePayParam param, Integer points); // 不一定需要 RefundResult doRefund(RefundParam param); RefundResult doPartialRefund(RefundParam param, BigDecimal amount); // 不一定需要 PayNotifyResult doPayNotify(PayNotifyParam param); PayNotifyResult doPayNotifyWithRetry(PayNotifyParam param); // 不一定需要 // ... 很多方法 } // ✅ 正确做法接口按职责拆分 public interface PayHandler { // 核心方法所有实现都需要 PayTypes payTypes(); PrePayResult doPrePay(PrePayParam param); RefundResult doRefund(RefundParam param); PayNotifyResult doPayNotify(PayNotifyParam param); } // 扩展接口需要优惠券功能的才实现 public interface CouponPayHandler extends PayHandler { PrePayResult doPrePayWithCoupon(PrePayParam param, Coupon coupon); } // 扩展接口需要积分功能的才实现 public interface PointsPayHandler extends PayHandler { PrePayResult doPrePayWithPoints(PrePayParam param, Integer points); } // 微信支付只实现核心接口不强迫实现不需要的方法 public class WechatPayHandler extends AbstractPayHandler { // 只需实现核心方法不需要实现优惠券、积分等方法 Override public PrePayResult doPrePay(PrePayParam param) { ... } } // 支付宝支付需要优惠券功能可以实现扩展接口 public class AlipayHandler extends AbstractPayHandler implements CouponPayHandler { Override public PrePayResult doPrePay(PrePayParam param) { ... } Override public PrePayResult doPrePayWithCoupon(PrePayParam param, Coupon coupon) { ... } }原则体现接口只包含必要的方法实现类不会被迫实现不需要的方法。五、单一职责原则SRP定义一个类只有一个引起它变化的原因。一个类只负责一项职责。代码体现java// ❌ 错误做法一个类做太多事情 public class BadPayService { public PrePayResult pay(PayBizParam param) { ... } // 支付 public RefundResult refund(RefundBizParam param) { ... } // 退款 public PayNotifyResult handleNotify(String data) { ... } // 回调 public void generateReport() { ... } // 报表 public void sendEmail(String to, String content) { ... } // 邮件 // 太多职责支付、退款、回调、报表、邮件... } // ✅ 正确做法职责分离 // 职责1支付处理 public interface PayHandler { PrePayResult doPrePay(PrePayParam param); } // 职责2退款处理 public interface RefundHandler { RefundResult doRefund(RefundParam param); } // 职责3回调处理 public interface NotifyHandler { PayNotifyResult doPayNotify(PayNotifyParam param); } // 职责4流水号生成独立组件 Component public class TradeNoGenerator { public String generateTradeNo() { ... } public String generateRefundNo() { ... } } // 职责5参数构建独立组件 Component public class PrePayParamBuilder { public PrePayParam build(PrePayContext context) { ... } } // 一个类只负责一件事 public class WechatPayHandler extends AbstractPayHandler { // 只负责微信支付的支付逻辑 Override public PrePayResult doPrePay(PrePayParam param) { // 调用微信API } }原则体现TradeNoGenerator只负责生成流水号WechatPayHandler只负责微信支付逻辑AlipayHandler只负责支付宝支付逻辑每个类只有一个修改理由六、依赖倒置原则DIP定义高层模块不应依赖低层模块两者都应依赖抽象。抽象不应依赖细节细节应依赖抽象。代码体现java// ❌ 错误做法高层模块依赖具体实现 public class BadPayService { private WechatPayHandler wechatHandler; // 依赖具体类 private AlipayHandler alipayHandler; // 依赖具体类 public void pay(String type, PayBizParam param) { if (WECHAT.equals(type)) { wechatHandler.doPrePay(param); } else if (ALIPAY.equals(type)) { alipayHandler.doPrePay(param); } } } // ✅ 正确做法依赖抽象接口 Service public class PayService { private final PayHandlerFactory factory; // 依赖工厂接口 public PayService(PayHandlerFactory factory) { this.factory factory; } public PrePayResult pay(PayTypes payType, PayBizParam param) { // 依赖 PayHandler 接口不依赖具体实现 PayHandler handler factory.getHandler(payType); PrePayParam prePayParam handler.buildPrePayParam(payType, param); return handler.doPrePay(prePayParam); } } // 抽象定义接口 public interface PayHandler { PrePayResult doPrePay(PrePayParam param); } // 具体实现依赖抽象 public class WechatPayHandler extends AbstractPayHandler { // 实现抽象接口 Override public PrePayResult doPrePay(PrePayParam param) { ... } } // 依赖注入将具体实现注入到抽象引用 Configuration public class PayConfig { Bean public PayService payService(ListPayHandler handlers) { PayHandlerFactory factory new PayHandlerFactory(handlers); return new PayService(factory); // 注入依赖 } }原则体现PayService高层依赖PayHandler接口抽象WechatPayHandler低层也依赖PayHandler接口抽象高层和低层都依赖抽象而不是相互依赖七、迪米特法则LoD定义一个对象应该对其他对象有最少的了解。只与直接的朋友通信。代码体现java// ❌ 错误做法跨越层级调用 public class BadPayService { public void pay(PayBizParam param) { WechatPayHandler handler new WechatPayHandler(); // 直接操作 handler 内部的组件 String tradeNo handler.getTradeNoGenerator().generate(); // 违反迪米特 handler.getHttpClient().post(url, data); // 违反迪米特 handler.getRedisTemplate().set(key, value); // 违反迪米特 } } // ✅ 正确做法只与直接朋友通信 public class WechatPayHandler extends AbstractPayHandler { // 封装内部细节不对外暴露 private final TradeNoGenerator tradeNoGenerator; private final HttpClient httpClient; private final RedisTemplate redisTemplate; Override public PrePayResult doPrePay(PrePayParam param) { // 内部使用不暴露给外部 String tradeNo tradeNoGenerator.generate(); String result httpClient.post(buildUrl(), buildBody(param)); redisTemplate.set(pay: tradeNo, result); return parseResult(result); } } // 使用方只与 PayHandler 交互不关心内部实现 Service public class PayService { private final PayHandlerFactory factory; public PrePayResult pay(PayTypes payType, PayBizParam param) { PayHandler handler factory.getHandler(payType); // 只调用 handler 的方法不调用其内部组件 PrePayParam prePayParam handler.buildPrePayParam(payType, param); return handler.doPrePay(prePayParam); // ✅ 只与直接朋友通信 } }原则体现PayService只与PayHandler交互不直接访问PayHandler内部的TradeNoGenerator、HttpClient等内部细节被封装在PayHandler实现类中八、总结对照表原则代码中的具体体现违反的后果开闭原则新增支付渠道只需加类不改现有代码每加一个渠道要改多处代码易出错里氏替换任何子类都能替换父类位置正常工作多态失效类型判断代码到处都是接口隔离PayHandler只有核心方法扩展接口分离实现类被迫实现不需要的方法单一职责TradeNoGenerator只负责生成流水号一个类改了影响多个不相关功能依赖倒置PayService依赖PayHandler接口高层依赖具体类换实现要改代码迪米特法则PayService只调用PayHandler方法类之间耦合过深难以维护九、一个完整的例子新增支付渠道java// 步骤1新增枚举值开闭原则 - 扩展 public enum PayTypes { WECHAT, ALIPAY, SIMULATE, CRYPTO_PAY // 新增加密货币支付 } // 步骤2新增实现类开闭原则 - 扩展 Component public class CryptoPayHandler extends AbstractPayHandler { // 里氏替换 - 正确实现父类契约 Override public PayTypes payTypes() { return PayTypes.CRYPTO_PAY; } Override public PrePayResult doPrePay(PrePayParam param) { // 单一职责 - 只负责加密货币支付逻辑 return cryptoApi.pay(param); } // 依赖倒置 - 依赖抽象接口不依赖具体实现 Autowired private CryptoApiClient cryptoApi; // 抽象接口 } // 步骤3使用方代码完全不需要修改开闭原则 Service public class PayService { public PrePayResult pay(PayTypes payType, PayBizParam param) { PayHandler handler factory.getHandler(payType); // 自动获取新渠道 return handler.doPrePay(handler.buildPrePayParam(payType, param)); } }六条原则在这个流程中的体现开闭新增类不改现有代码里氏CryptoPayHandler能替换PayHandler使用接口隔离只实现PayHandler必需方法单一职责CryptoPayHandler只负责加密支付依赖倒置依赖CryptoApiClient接口迪米特外部只调用doPrePay不关心内部实现里氏替换和依赖倒置感觉比较类似都是只依赖接口不依赖具体实现// 依赖倒置关注依赖的方向是否正确 // 里氏替换问的是 // 用 SimulatePayHandler 替换 AbstractPayHandler 后程序还能正常运行吗 // 依赖倒置问的是 // PayService 是依赖了 PayHandler 接口好还是依赖了 WechatPayHandler 具体类坏三、详细对比维度里氏替换原则LSP依赖倒置原则DIP核心问题继承后的行为契约依赖的方向和粒度作用对象父子类之间的关系模块/类之间的依赖关系关注时机编写子类时设计架构时违反后果多态失效运行时异常代码耦合难以修改解决手段正确继承不改变父类行为面向接口编程四、代码示例对比场景支付系统java// 依赖倒置DIP示例 // 关注依赖关系是否正确 // ❌ 违反依赖倒置高层依赖低层 public class PayService { private WechatPayHandler wechatHandler; // 依赖具体类 private AlipayHandler alipayHandler; // 依赖具体类 // 问题换支付方式要改代码 } // ✅ 符合依赖倒置依赖抽象 public class PayService { private PayHandler handler; // 依赖接口抽象 // 好处换任何支付方式都不改代码 } // 里氏替换LSP示例 // 关注继承后行为是否正确 // 父类定义 public abstract class AbstractPayHandler { // 约定返回的金额必须大于0 public PrePayParam buildPrePayParam(PayBizParam bizParam) { PrePayParam param new PrePayParam(); param.setAmount(bizParam.getAmount()); // 原样设置 return param; } } // ❌ 违反里氏替换子类改变了父类行为 public class BadSimulateHandler extends AbstractPayHandler { Override public PrePayParam buildPrePayParam(PayBizParam bizParam) { PrePayParam param super.buildPrePayParam(bizParam); // 恶意修改金额强制设为0违反父类金额0的约定 param.setAmount(BigDecimal.ZERO); return param; } } // 使用方符合依赖倒置但会被里氏替换坑 public class PayService { private PayHandler handler; // ✅ 依赖倒置正确 public void pay(PayBizParam param) { PrePayParam prePayParam handler.buildPrePayParam(param); // 如果 handler 是 BadSimulateHandler金额变成了0 // 程序可能异常 → 违反了里氏替换 } }五、两个原则的关系java// 依赖倒置是骨架里氏替换是血肉 // 依赖倒置定义架构都依赖接口 public interface PayHandler { PrePayParam buildPrePayParam(PayBizParam param); } // 里氏替换保证实现子类不能破坏父类约定 public abstract class AbstractPayHandler implements PayHandler { // 约定1tradeNo 不能为空 // 约定2amount 必须大于0 // 约定3返回的 notifyUrl 必须是 https public PrePayParam buildPrePayParam(PayBizParam bizParam) { PrePayParam param new PrePayParam(); param.setTradeNo(buildTradeNo()); // 约定1 param.setAmount(bizParam.getAmount()); // 约定2必须0 param.setNotifyUrl(buildHttpsUrl()); // 约定3 return param; } } // 子类遵守里氏替换不破坏父类约定 public class WechatPayHandler extends AbstractPayHandler { Override public PrePayParam buildPrePayParam(PayBizParam bizParam) { PrePayParam param super.buildPrePayParam(bizParam); // 遵守约定 param.setOpenId(bizParam.getOpenId()); // 只扩展不破坏 return param; } }六、违反时的错误信息对比java// 违反依赖倒置编译期就能发现 PayService service new PayService(); service.setHandler(new WechatPayHandler()); // OK service.setHandler(string); // ❌ 编译错误类型不匹配 // 违反里氏替换运行时才能发现 AbstractPayHandler handler new BadSimulateHandler(); PrePayParam param handler.buildPrePayParam(bizParam); if (param.getAmount().compareTo(BigDecimal.ZERO) 0) { throw new RuntimeException(金额必须大于0); // 运行时才炸 }七、记忆口诀原则记忆口诀思考问题依赖倒置面向接口不面向实现依赖的是抽象还是具体里氏替换子类替父行为不变子类替换父类后程序还能跑吗八、总结java// 依赖倒置定义用什么 PayHandler handler factory.getHandler(payType); // 用接口不用具体类 // 里氏替换保证怎么用 handler.doPrePay(param); // 无论 handler 是什么子类都能正常工作 // 两者配合 // 依赖倒置让你面向接口编程架构层面 // 里氏替换让你放心使用多态实现层面一句话总结依赖倒置告诉你依赖什么依赖抽象不依赖具体里氏替换保证你依赖的东西没问题子类替换后还能正常工作两者不是类似而是互补的关系。依赖倒置是设计时的选择里氏替换是实现时的约束。所有原则就上面种吗不止这6种这只是面向对象设计中最经典的6大原则SOLID 迪米特。完整的设计原则体系更丰富让我帮你梳理。一、设计原则体系总览分类原则核心思想核心原则单一职责、开闭、里氏替换、接口隔离、依赖倒置OO设计的基石包/组件原则复用发布等价、共同封闭、共同复用、无环依赖、稳定依赖、稳定抽象包/模块级别的设计其他重要原则迪米特、组合优于继承、好莱坞原则、最少惊讶补充性的最佳实践二、六大核心原则SOLID 迪米特你已经了解的这6个缩写原则英文S单一职责Single ResponsibilityO开闭原则Open-ClosedL里氏替换Liskov SubstitutionI接口隔离Interface SegregationD依赖倒置Dependency InversionLoD迪米特法则Law of Demeter三、包/组件级别原则6个这些原则来自《敏捷软件开发》一书用于指导模块/包/组件的设计。1. 复用发布等价原则REP定义复用的粒度就是发布的粒度。java// ❌ 违反一个包既有支付工具类又有日志工具类 // 想要复用支付工具却不得不带上日志类 // ✅ 符合按功能拆分成独立包 com.cloud.pay.utils // 支付相关工具独立发布 com.cloud.log.utils // 日志相关工具独立发布2. 共同封闭原则CCP定义应该一起修改的类应该放在同一个包里。java// ✅ 符合支付相关的类放在一起 com.cloud.pay.handler // 支付处理器 com.cloud.pay.model // 支付模型 com.cloud.pay.exception // 支付异常 // 修改支付逻辑时只影响这个包 // ❌ 违反支付类和订单类混在一起 com.cloud.common // 什么都往里放3. 共同复用原则CRP定义不应该强迫用户依赖他们不需要的类。java// ❌ 违反想要用支付功能却被迫依赖退款、对账功能 public interface PayHandler { void pay(); void refund(); // 不需要退款功能的用户也得依赖 void reconcile(); // 不需要对账功能的用户也得依赖 } // ✅ 符合接口按功能拆分 public interface PayHandler { void pay(); } public interface RefundHandler { void refund(); } public interface ReconcileHandler { void reconcile(); }4. 无环依赖原则ADP定义包的依赖关系图中不允许出现环。java// ❌ 违反循环依赖 // pay包 依赖 notify包 // notify包 依赖 pay包 → 循环依赖 // ✅ 符合引入抽象包打破循环 // pay包 依赖 common包 // notify包 依赖 common包 // common包 不依赖任何包5. 稳定依赖原则SDP定义依赖必须指向更稳定的方向。java// ❌ 违反不稳定的包依赖稳定的包方向反了 // 经常变化的 pay-handler 包 依赖 稳定的 pay-model 包 ✅ 正确 // 稳定的 pay-model 包 依赖 变化的 pay-handler 包 ❌ 错误 // ✅ 符合稳定的包被依赖不依赖别人 // pay-model稳定← pay-handler不稳定6. 稳定抽象原则SAP定义稳定的包应该是抽象的不稳定的包应该是具体的。java// ✅ 符合 // pay-model稳定→ 定义为接口抽象 public interface Payment { ... } // pay-handler不稳定→ 具体实现类 public class WechatPayment implements Payment { ... }四、其他重要设计原则1. 组合优于继承原则Composition over Inheritance定义优先使用对象组合而不是类继承。java// ❌ 继承过度使用 public class Animal { ... } public class Dog extends Animal { ... } public class Cat extends Animal { ... } // 问题继承层次过深难以维护 // ✅ 组合 public class Animal { private MoveStrategy moveStrategy; // 组合移动策略 private SoundStrategy soundStrategy; // 组合发声策略 } public class Dog { private Animal animal new Animal(new RunStrategy(), new BarkStrategy()); }在你的支付代码中java// 组合优于继承的应用 Component public class WechatPayHandler extends AbstractPayHandler { // 组合注入其他组件而不是继承 Autowired private TradeNoGenerator tradeNoGenerator; // ✅ 组合 Autowired private HttpClient httpClient; // ✅ 组合 // 而不是 // public class WechatPayHandler extends TradeNoGenerator ❌ 继承 }2. 好莱坞原则Hollywood Principle定义别打电话给我们我们会打给你。控制反转IoC的思想。java// 好莱坞原则的体现 // ❌ 违反子类主动调用父类依赖具体时机 public class BadSimulateHandler extends AbstractPayHandler { public void pay() { if (needRetry()) { // 子类决定是否重试 retry(); } super.pay(); } } // ✅ 符合父类控制流程子类只实现钩子 public abstract class AbstractPayHandler { public final void process() { beforePay(); // 钩子 doPay(); // 抽象方法 afterPay(); // 钩子 } protected void beforePay() {} // 子类可重写但不决定调用时机 } public class SimulatePayHandler extends AbstractPayHandler { Override protected void beforePay() { // 只管实现不管何时调用父类决定 } }3. 最少惊讶原则Principle of Least Astonishment定义代码的行为应该符合用户的预期不要让人惊讶。java// ❌ 违反行为出乎意料 public class Calculator { public int add(int a, int b) { return a - b; // 惊讶叫add却是减法 } } // ✅ 符合名实相符 public class Calculator { public int add(int a, int b) { return a b; // 符合预期 } } // 在你的支付代码中 public class SimulatePayHandler extends AbstractPayHandler { // ✅ 方法名和实际行为一致 Override public PrePayResult doPrePay(PrePayParam param) { log.info(模拟支付); // 模拟支付不真实调用接口 return PrePayResult.success(); } }4. 不要重复自己原则DRY - Dont Repeat Yourself定义每一项知识在系统中都应该有单一、明确、权威的表示。java// ❌ 违反重复代码 public class WechatPayHandler { public PrePayParam buildParam() { String tradeNo generateTradeNo(); // 重复 BigDecimal amount getAmount(); // 重复 // ... } } public class AlipayHandler { public PrePayParam buildParam() { String tradeNo generateTradeNo(); // 重复 BigDecimal amount getAmount(); // 重复 // ... } } // ✅ 符合提取公共逻辑 public abstract class AbstractPayHandler { public PrePayParam buildParam() { String tradeNo generateTradeNo(); // 只写一次 BigDecimal amount getAmount(); // 只写一次 // ... } }5. 高内聚低耦合原则High Cohesion Low Coupling定义模块内部紧密相关模块之间松散依赖。java// 你的代码完美体现了这个原则 // 高内聚每个类职责单一 public class TradeNoGenerator { ... } // 只负责生成流水号 public class SignUtil { ... } // 只负责签名 public class WechatPayHandler { ... } // 只负责微信支付 // 低耦合通过接口依赖 public class PayService { private PayHandler handler; // 依赖接口不依赖具体类 }6. YAGNI 原则You Aint Gonna Need It定义不要添加你当前不需要的功能。java// ❌ 违反过度设计 public interface PayHandler { void pay(); void refund(); void query(); void cancel(); void notify(); void retry(); // 当前不需要 void backup(); // 当前不需要 void report(); // 当前不需要 } // ✅ 符合只实现需要的功能 public interface PayHandler { void pay(); // 当前需要 void refund(); // 当前需要 // 其他功能等需要时再加 }7. 契约式设计Design by Contract定义通过前置条件、后置条件、不变量来定义接口契约。javapublic abstract class AbstractPayHandler { // 契约定义 public PrePayParam buildPrePayParam(PayBizParam bizParam) { // 前置条件参数不能为空 assert bizParam ! null : bizParam不能为空; assert bizParam.getAmount() ! null : 金额不能为空; assert bizParam.getAmount().compareTo(BigDecimal.ZERO) 0 : 金额必须大于0; PrePayParam param new PrePayParam(); param.setTradeNo(buildTradeNo()); param.setAmount(bizParam.getAmount()); // 后置条件返回结果不能为空tradeNo不能为空 assert param ! null : 返回结果不能为空; assert StringUtils.isNotBlank(param.getTradeNo()) : tradeNo不能为空; return param; } }五、完整原则清单序号原则英文关注层次1单一职责SRP类级别2开闭原则OCP类/模块级别3里氏替换LSP继承关系4接口隔离ISP接口设计5依赖倒置DIP架构级别6迪米特法则LoD方法调用7复用发布等价REP包级别8共同封闭CCP包级别9共同复用CRP包级别10无环依赖ADP包级别11稳定依赖SDP包级别12稳定抽象SAP包级别13组合优于继承-类设计14好莱坞原则-控制反转15最少惊讶-API设计16DRY-代码复用17高内聚低耦合-模块设计18YAGNI-功能规划19契约式设计DbC接口契约六、优先级建议对于日常开发按重要性排序优先级原则必须掌握程度⭐⭐⭐⭐⭐单一职责、开闭原则、依赖倒置必须熟练运用⭐⭐⭐⭐里氏替换、接口隔离、DRY必须理解⭐⭐⭐迪米特、组合优于继承、高内聚低耦合尽量遵守⭐⭐好莱坞、最少惊讶、YAGNI了解即可⭐REP、CCP、ADP等包级原则架构师需掌握对于你当前的学习阶段先把SOLID 迪米特 DRY这8个掌握好就足够了。包级别原则通常是在设计大型系统时才需要考虑。本回答由 AI 生成内容仅供参考请仔细甄别。

相关文章:

设计模式原则,请针对具体代码说明

设计原则总结:结合支付模块代码的具体说明一、六大设计原则概览原则英文核心含义开闭原则Open-Closed Principle对扩展开放,对修改关闭里氏替换Liskov Substitution子类型必须能替换父类型接口隔离Interface Segregation接口应该小而专一单一职责Single …...

如何快速掌握AMD Ryzen调试技巧:SMUDebugTool的完整使用指南

如何快速掌握AMD Ryzen调试技巧:SMUDebugTool的完整使用指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: http…...

NIUSHOP V6 多商户 B2B2C 商城系统介绍

多商户 B2B2C 商城系统是专为企业打造“平台多商户”协同运营的电商生态,支持平台自营第三方店铺入驻混合模式,覆盖实物电商、本地生活、O2O 全场景,支持多城市多商圈精细化运营,实现商品、订单、资金、数据全链路统一管理。 系统…...

ComfyUI极速上手指南:零基础搭建高效AI绘图工作流

1. ComfyUI初印象:为什么选择这个AI绘图神器 第一次接触ComfyUI时,我完全被它独特的节点式操作方式吸引了。与常见的WebUI不同,ComfyUI把整个AI绘图过程拆解成一个个可视化模块,就像搭积木一样自由组合。这种设计理念让创作过程变…...

开关电源EMI降噪实战:AC/DC和DC/DC滤波电路设计避坑指南

开关电源EMI降噪实战:AC/DC和DC/DC滤波电路设计避坑指南 在工业自动化设备和医疗电子系统中,开关电源的电磁干扰(EMI)问题常常成为产品通过认证的"拦路虎"。一位资深电源工程师曾分享过他的经历:某型医疗监…...

【电子通识】为什么PCB能短接还要用0Ω电阻?0欧电阻怎么做降额?

简介 市面上有一种电阻叫0Ω电阻,又称跨接电阻,是一种标称阻值为0的特殊电阻。有没有想过,用PCB直接就可以实现短接变成0Ω的功能,那为什么还需要焊接一个0Ω电阻呢? 0Ω电阻是一种特殊用途的电阻,与常规贴…...

前端+AI项目学习笔记day8

二十、分页效果实现二十一、知识文章新增弹窗编写ArticleDialog.vue组件<template><el-dialogtitle"文章详情"v-model"dialogVisible"width"50%"close"handleClose"><el-form :model"formData" :rules"…...

实测DeepSeek-OCR-WEBUI:中文识别精准,复杂背景也能搞定

实测DeepSeek-OCR-WEBUI&#xff1a;中文识别精准&#xff0c;复杂背景也能搞定 1. 从“看不清”到“读得懂”的跨越 你有没有遇到过这样的场景&#xff1f;拍了一张会议白板的照片&#xff0c;上面的字迹有些潦草&#xff0c;背景还有各种投影仪的影子&#xff0c;想用手机上…...

Cosmos-Reason1-7B在复杂网络协议分析中的应用场景

Cosmos-Reason1-7B在复杂网络协议分析中的应用场景 网络工程师的日常&#xff0c;常常伴随着海量的数据包和复杂的协议交互。面对一个动辄几个G的抓包文件&#xff0c;如何快速定位一次握手失败的原因&#xff0c;或者解释某个应用为何响应缓慢&#xff0c;往往需要深厚的协议…...

深求·墨鉴在办公场景实战:快速整理会议纪要,手写笔记一键电子化

深求墨鉴在办公场景实战&#xff1a;快速整理会议纪要&#xff0c;手写笔记一键电子化 1. 办公文档数字化的痛点与解决方案 在日常办公中&#xff0c;我们经常面临这样的困扰&#xff1a;重要会议的手写笔记难以整理&#xff0c;白板讨论内容无法有效留存&#xff0c;纸质文档…...

超元力VR大空间:以技术为桥,解锁沉浸式体验新可能

当数字技术逐渐融入日常生活&#xff0c;人们对体验的需求不再局限于“观看”&#xff0c;而是渴望“参与”和“沉浸”。超元力VR大空间&#xff0c;打破了传统VR体验的局限&#xff0c;以成熟的技术支撑和多元的内容呈现&#xff0c;让人们在有限的物理场地中&#xff0c;感受…...

二叉树的右透视图

思路如下&#xff1a; 借助二叉树的层次遍历&#xff0c;用两个队列&#xff0c;一个队列存当前遍历的层&#xff0c;另一个队列存下一层。 当前队列是最后一个节点的时候&#xff0c;最后这个节点就是右透视图需要展示的节点。在遍历当前队列的时候&#xff0c;把下一层加入下…...

FID指标避坑指南:当你的生成模型分数突然飙升时该怎么办?

FID指标避坑指南&#xff1a;当生成模型分数异常飙升时的诊断与应对策略 1. 理解FID指标的本质与常见陷阱 FID&#xff08;Frchet Inception Distance&#xff09;作为生成对抗网络&#xff08;GAN&#xff09;和扩散模型&#xff08;Diffusion Models&#xff09;领域最广泛使…...

G-Helper终极指南:如何用轻量工具彻底替代Armoury Crate提升ROG笔记本性能

G-Helper终极指南&#xff1a;如何用轻量工具彻底替代Armoury Crate提升ROG笔记本性能 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, F…...

如何免费将网易云音乐NCM格式转换为MP3/FLAC:ncmdumpGUI完整指南

如何免费将网易云音乐NCM格式转换为MP3/FLAC&#xff1a;ncmdumpGUI完整指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾经下载了网易云音乐的NCM…...

WarcraftHelper:魔兽争霸3现代兼容性终极解决方案

WarcraftHelper&#xff1a;魔兽争霸3现代兼容性终极解决方案 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper WarcraftHelper是一款专为魔兽争霸3设计…...

Zotero插件市场:如何在Zotero 7+中一键发现和安装最佳插件?

Zotero插件市场&#xff1a;如何在Zotero 7中一键发现和安装最佳插件&#xff1f; 【免费下载链接】zotero-addons Zotero Add-on Market | Zotero插件市场 | Browsing, installing, and reviewing plugins within Zotero 项目地址: https://gitcode.com/gh_mirrors/zo/zoter…...

HeyGem数字人视频生成系统实战:制作新年祝福短视频批量模板

HeyGem数字人视频生成系统实战&#xff1a;制作新年祝福短视频批量模板 新年将至&#xff0c;无论是企业给客户送祝福&#xff0c;还是团队给员工发问候&#xff0c;制作一段温馨的新年祝福视频都是很有仪式感的事情。但问题来了&#xff1a;如果公司有几十位员工&#xff0c;…...

如何3分钟解锁网易云音乐NCM加密文件:ncmdumpGUI终极指南

如何3分钟解锁网易云音乐NCM加密文件&#xff1a;ncmdumpGUI终极指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾从网易云音乐下载了心爱的歌曲&a…...

小红书数据采集终极指南:高效Python爬虫实战技巧解析

小红书数据采集终极指南&#xff1a;高效Python爬虫实战技巧解析 【免费下载链接】xhs 基于小红书 Web 端进行的请求封装。https://reajason.github.io/xhs/ 项目地址: https://gitcode.com/gh_mirrors/xh/xhs 小红书作为中国领先的社交电商平台&#xff0c;汇聚了海量的…...

终极指南:如何用XUnity.AutoTranslator轻松玩转全球Unity游戏

终极指南&#xff1a;如何用XUnity.AutoTranslator轻松玩转全球Unity游戏 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 你是否曾因语言障碍而错过心仪的外语游戏&#xff1f;XUnity.AutoTranslator这款…...

LLM系列:1.python入门:5.列表型对象 (List)

列表型对象 (List) 一. 列表基础 1. 列表创建 list可以存储任意类型对象 (1).直接创建 lst [1, 2, 3, 4](2).列表推导式 ①.表推导式的语法结构基本形式&#xff1a; [表达式 for 变量 in 可迭代对象]带条件&#xff1a; [表达式 for 变量 in 可迭代对象 if 条件]例子&#xf…...

钰泰ETA9742 支持边充边放 移动电源充电集成芯片

各位好&#xff0c;今天给大家介绍一款在便携充放电领域应用很广泛的芯片 ——ETA9742。首先从核心定位来说&#xff0c;ETA9742 是一款开关式锂离子电池充电器&#xff0c;专门针对 4.2V 规格的锂电池设计&#xff0c;采用 ESOP8 封装&#xff0c;是电池充放电场景里的一体化解…...

欧盟CE认证的PED压力容器指令认证

欧盟 CE 认证的 PED 压力容器指令认证&#xff0c;全称是 Pressure Equipment Directive (PED) 2014/68/EU&#xff08;压力设备指令&#xff09;&#xff0c;是欧盟针对承压类设备的强制性安全认证&#xff0c;属于 CE 认证体系下的核心指令之一。简单说&#xff0c;它是进入欧…...

魔兽争霸3辅助工具:让你的经典游戏焕发新生

魔兽争霸3辅助工具&#xff1a;让你的经典游戏焕发新生 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 你是否还在为魔兽争霸3的画面限制而苦恼&#…...

Miniconda-Python3.10镜像使用指南:快速创建独立环境,避免依赖冲突

Miniconda-Python3.10镜像使用指南&#xff1a;快速创建独立环境&#xff0c;避免依赖冲突 1. 为什么需要Python环境管理 在日常开发中&#xff0c;我们经常会遇到这样的问题&#xff1a; 项目A需要Python 3.7和TensorFlow 1.15项目B需要Python 3.10和TensorFlow 2.8系统默认…...

借助爱毕业(aibiye),数学建模论文的复现与排版更加智能化、规范化

还在为论文写作头痛&#xff1f;特别是数学建模的优秀论文复现与排版&#xff0c;时间紧、任务重&#xff0c;AI工具能帮上大忙吗&#xff1f;今天&#xff0c;我们评测10款热门AI论文写作工具&#xff0c;帮你精准筛选最适合的助手。 aibiye&#xff1a;专注于语法润色与结构…...

爱毕业(aibiye)的AI技术可提升数学建模论文的复现质量,并简化排版流程

还在为论文写作头痛&#xff1f;特别是数学建模的优秀论文复现与排版&#xff0c;时间紧、任务重&#xff0c;AI工具能帮上大忙吗&#xff1f;今天&#xff0c;我们评测10款热门AI论文写作工具&#xff0c;帮你精准筛选最适合的助手。 aibiye&#xff1a;专注于语法润色与结构…...

5分钟搞定!用Qwen3-Embedding-4B为你的网站添加智能搜索功能

5分钟搞定&#xff01;用Qwen3-Embedding-4B为你的网站添加智能搜索功能 1. 引言&#xff1a;为什么需要智能搜索&#xff1f; 传统网站搜索功能通常基于关键词匹配&#xff0c;当用户输入"苹果"时&#xff0c;系统只会机械地查找包含这两个字的页面&#xff0c;无…...

3个实用技巧:如何用ncmdump轻松解密网易云音乐NCM文件

3个实用技巧&#xff1a;如何用ncmdump轻松解密网易云音乐NCM文件 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM加密文件无法在其他播放器播放而烦恼吗&#xff1f;今天&#xff0c;我将为你介绍一款简单…...