software-design-principles
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSoftware Design Principles
软件设计原则
This skill helps the agent guide a user through software design principles—guidelines for creating software systems that are maintainable, scalable, reusable, and loosely coupled. Apply the principles below when discussing design, reviewing code, or suggesting improvements.
本技能可帮助Agent引导用户了解软件设计原则——这些是创建可维护、可扩展、可复用且低耦合软件系统的准则。在讨论设计、评审代码或提出改进建议时,可应用以下原则。
Instructions
使用说明
When this skill is invoked:
- For design discussions or questions — Use the principles in this document (SOLID, DRY, KISS, etc.) to explain concepts, compare bad vs better examples, and suggest improvements.
- For design/code review output — Use Template A when there are findings (critical issues or suggestions); use Template B when there are no issues. Follow the exact structure and section headings defined in the templates.
- When suggesting refactors — Reference the relevant principle by name and point to the "What it achieves" and examples in this skill.
调用本技能时:
- 针对设计讨论或问题 —— 使用本文档中的原则(SOLID、DRY、KISS等)解释概念,对比不良与优化示例,并提出改进建议。
- 针对设计/代码评审输出 —— 若发现问题(严重问题或建议),使用模板A;若无问题,使用模板B。严格遵循模板中定义的结构和章节标题。
- 提出重构建议时 —— 引用相关原则的名称,并参考本技能中的“达成目标”和示例内容。
When to Use
适用场景
- Design principles
- Clean code
- Refactoring a software system
- Suggesting improvements
- Structuring your code
- Managing class dependencies
- Maintaining a software system
- Reviewing code
- 设计原则咨询
- 整洁代码编写
- 软件系统重构
- 代码改进建议
- 代码结构规划
- 类依赖管理
- 软件系统维护
- 代码评审
SOLID Principles
SOLID原则
SOLID is the most widely known object-oriented design principle set.
SOLID是最广为人知的面向对象设计原则集合。
What SOLID Achieves (Overall)
SOLID整体达成目标
- Maintainability — Changes are localized; fewer side effects.
- Low coupling — Modules depend on abstractions, not concrete implementations.
- High cohesion — Each class has a focused, single purpose.
- Testability — Dependencies can be mocked or stubbed.
- Extensibility — New behavior added via new code, not by modifying existing code.
- 可维护性 —— 变更仅影响局部区域;副作用更少。
- 低耦合 —— 模块依赖抽象而非具体实现。
- 高内聚 —— 每个类都有明确、单一的职责。
- 可测试性 —— 依赖可被模拟或存根化。
- 可扩展性 —— 通过新增代码实现新功能,无需修改现有代码。
S – Single Responsibility Principle (SRP)
S – 单一职责原则(SRP)
Definition: A class should have only one reason to change.
What it achieves (agent context):
- Maintainability — When reviewing code, if a class handles persistence, validation, and notification, suggest splitting so each has one responsibility.
- Clear responsibilities — Name classes by their single concern (e.g. ,
UserPersistenceService).EmailNotificationService - Easier testing — One responsibility per class means focused unit tests and simpler mocks.
- Inference: If you see multiple unrelated methods (e.g. save + send email + log), recommend extracting separate classes.
Example
Bad design (one class, multiple reasons to change):
java
class UserService {
void saveUser(User user) { /* DB */ }
void sendEmail(User user) { /* SMTP */ }
void validateUser(User user) { /* rules */ }
}Better design (one responsibility per class):
java
class UserRepository {
void saveUser(User user) { /* DB only */ }
}
class EmailService {
void sendEmail(User user) { /* SMTP only */ }
}
class UserValidator {
boolean isValid(User user) { /* validation only */ }
}定义: 一个类应该只有一个引起变化的原因。
在Agent场景下的达成目标:
- 可维护性 —— 评审代码时,若一个类同时处理持久化、验证和通知功能,建议拆分,使每个类仅负责一项职责。
- 职责清晰 —— 根据类的单一关注点命名(例如、
UserPersistenceService)。EmailNotificationService - 测试更简单 —— 每个类仅负责一项职责意味着单元测试更聚焦,模拟实现更简单。
- 推理判断: 若发现类中包含多个不相关方法(例如保存+发送邮件+日志),建议提取为独立类。
示例
不良设计(一个类,多个变化原因):
java
class UserService {
void saveUser(User user) { /* DB */ }
void sendEmail(User user) { /* SMTP */ }
void validateUser(User user) { /* rules */ }
}优化设计(每个类一项职责):
java
class UserRepository {
void saveUser(User user) { /* DB only */ }
}
class EmailService {
void sendEmail(User user) { /* SMTP only */ }
}
class UserValidator {
boolean isValid(User user) { /* validation only */ }
}O – Open/Closed Principle (OCP)
O – 开闭原则(OCP)
Definition: Software entities should be open for extension but closed for modification.
What it achieves (agent context):
- Prevents regression — Adding new behavior does not require changing existing, tested code.
- Extension without modification — Prefer interfaces/abstract classes and new implementations over editing existing conditionals.
- Inference: When you see or long
if (type == "X")on types, suggest polymorphism (e.g. strategy, factory) so new types are added as new classes.switch
Example
Bad (modification required for every new type):
java
class ReportExporter {
void export(String type, Data data) {
if (type.equals("PDF")) { /* PDF */ }
else if (type.equals("DOC")) { /* DOC */ }
else if (type.equals("CSV")) { /* CSV */ }
}
}Better (extend by adding new classes; no change to existing logic):
java
interface ReportGenerator {
void generate(Data data);
}
class PdfReportGenerator implements ReportGenerator {
@Override public void generate(Data data) { /* PDF */ }
}
class CsvReportGenerator implements ReportGenerator {
@Override public void generate(Data data) { /* CSV */ }
}定义: 软件实体应该对扩展开放,对修改关闭。
在Agent场景下的达成目标:
- 防止回归问题 —— 添加新功能无需修改已测试的现有代码。
- 无需修改即可扩展 —— 优先使用接口/抽象类和新实现,而非编辑现有条件判断。
- 推理判断: 若发现或针对类型的长
if (type == "X")语句,建议使用多态(例如策略模式、工厂模式),使新增类型通过新增类实现。switch
示例
不良设计(新增类型需修改代码):
java
class ReportExporter {
void export(String type, Data data) {
if (type.equals("PDF")) { /* PDF */ }
else if (type.equals("DOC")) { /* DOC */ }
else if (type.equals("CSV")) { /* CSV */ }
}
}优化设计(通过新增类扩展;无需修改现有逻辑):
java
interface ReportGenerator {
void generate(Data data);
}
class PdfReportGenerator implements ReportGenerator {
@Override public void generate(Data data) { /* PDF */ }
}
class CsvReportGenerator implements ReportGenerator {
@Override public void generate(Data data) { /* CSV */ }
}L – Liskov Substitution Principle (LSP)
L – 里氏替换原则(LSP)
Definition: Subtypes must be replaceable for their base types without breaking behavior.
What it achieves (agent context):
- Correct inheritance — Subclasses must honor the contract of the base (preconditions, postconditions, invariants).
- Reliable polymorphism — Callers can use the base type without knowing the concrete subtype; no surprises (e.g. throwing in a case that base does not).
- Inference: If a subclass weakens preconditions, strengthens postconditions, or throws new exceptions, it likely violates LSP. Prefer composition or more specific interfaces (e.g. vs
FlyingBird) when not all subtypes support the same operations.Bird
Example
Bad (subtype cannot fulfill base contract — penguin cannot fly):
java
class Bird {
void fly() { /* assume all birds fly */ }
}
class Penguin extends Bird {
@Override void fly() { throw new UnsupportedOperationException("Penguins can't fly"); }
}Better (separate interface for flying; only flying birds implement it):
java
interface Bird { }
interface FlyingBird extends Bird {
void fly();
}
class Sparrow implements FlyingBird {
@Override public void fly() { /* fly */ }
}
class Penguin implements Bird { /* no fly() */ }定义: 子类型必须能够替换其基类型而不破坏原有行为。
在Agent场景下的达成目标:
- 正确的继承关系 —— 子类必须遵守基类的契约(前置条件、后置条件、不变量)。
- 可靠的多态性 —— 调用者可使用基类型而无需了解具体子类型;不会出现意外情况(例如抛出基类未定义的异常)。
- 推理判断: 若子类弱化前置条件、强化后置条件或抛出新异常,则可能违反LSP。当并非所有子类型都支持相同操作时,优先使用组合或更具体的接口(例如vs
FlyingBird)。Bird
示例
不良设计(子类无法满足基类契约——企鹅不会飞):
java
class Bird {
void fly() { /* assume all birds fly */ }
}
class Penguin extends Bird {
@Override void fly() { throw new UnsupportedOperationException("Penguins can't fly"); }
}优化设计(为会飞的鸟类单独定义接口;仅会飞的鸟类实现该接口):
java
interface Bird { }
interface FlyingBird extends Bird {
void fly();
}
class Sparrow implements FlyingBird {
@Override public void fly() { /* fly */ }
}
class Penguin implements Bird { /* no fly() */ }I – Interface Segregation Principle (ISP)
I – 接口隔离原则(ISP)
Definition: Clients should not be forced to depend on interfaces they do not use.
What it achieves (agent context):
- Smaller, focused interfaces — Clients depend only on the methods they need.
- Flexibility — Implementations can provide only relevant behavior; no dummy/empty methods.
- Reduced complexity — Easier to mock and test; changes to one capability do not force changes in unrelated clients.
- Inference: When you see a "fat" interface with many methods and implementations that leave some no-op or throwing, suggest splitting into role interfaces (e.g. ,
Workable).Eatable
Example
Bad (worker must implement even if not needed; robot cannot eat):
eat()java
interface Worker {
void work();
void eat();
}
class Human implements Worker {
public void work() { /* work */ }
public void eat() { /* eat */ }
}
class Robot implements Worker {
public void work() { /* work */ }
public void eat() { } // no-op or throw — forced dependency
}Better (clients depend only on what they use):
java
interface Workable {
void work();
}
interface Eatable {
void eat();
}
class Human implements Workable, Eatable {
public void work() { /* work */ }
public void eat() { /* eat */ }
}
class Robot implements Workable {
public void work() { /* work */ }
}定义: 客户端不应被迫依赖其不需要的接口。
在Agent场景下的达成目标:
- 更小、更聚焦的接口 —— 客户端仅依赖其需要的方法。
- 灵活性 —— 实现类仅需提供相关行为;无需编写空实现或抛出异常的方法。
- 降低复杂度 —— 模拟和测试更简单;某一功能的变更不会影响不相关的客户端。
- 推理判断: 若发现“臃肿”的接口包含多个方法,且实现类中存在空实现或抛出异常的方法,建议拆分为角色接口(例如、
Workable)。Eatable
示例
不良设计(Worker必须实现即使不需要;机器人无法进食):
eat()java
interface Worker {
void work();
void eat();
}
class Human implements Worker {
public void work() { /* work */ }
public void eat() { /* eat */ }
}
class Robot implements Worker {
public void work() { /* work */ }
public void eat() { } // no-op or throw — forced dependency
}优化设计(客户端仅依赖其需要的接口):
java
interface Workable {
void work();
}
interface Eatable {
void eat();
}
class Human implements Workable, Eatable {
public void work() { /* work */ }
public void eat() { /* eat */ }
}
class Robot implements Workable {
public void work() { /* work */ }
}D – Dependency Inversion Principle (DIP)
D – 依赖倒置原则(DIP)
Definition: High-level modules should not depend on low-level modules; both should depend on abstractions.
What it achieves (agent context):
- Loose coupling — High-level logic does not depend on concrete payment gateways, repositories, or APIs.
- Testability — Abstractions (interfaces) can be mocked in tests.
- Enables Dependency Injection — Frameworks (e.g. Spring) inject implementations; swapping implementations does not require changing high-level code.
- Inference: When you see inside a high-level class, suggest depending on an interface and injecting the implementation (constructor or setter).
new ConcreteService()
Example
Bad (high-level depends on concrete low-level):
java
class OrderService {
private PaymentService payment = new PaymentService(); // tight coupling
void placeOrder(Order order) {
payment.charge(order.getTotal());
}
}Better (depend on abstraction; inject implementation):
java
interface PaymentProcessor {
void charge(BigDecimal amount);
}
class OrderService {
private final PaymentProcessor payment;
OrderService(PaymentProcessor payment) {
this.payment = payment;
}
void placeOrder(Order order) {
payment.charge(order.getTotal());
}
}Used heavily in Spring Dependency Injection (constructor injection preferred).
定义: 高层模块不应依赖低层模块;两者都应依赖抽象。
在Agent场景下的达成目标:
- 低耦合 —— 高层逻辑不依赖具体的支付网关、仓库或API。
- 可测试性 —— 抽象(接口)可在测试中被模拟。
- 支持依赖注入 —— 框架(例如Spring)注入实现类;替换实现类无需修改高层代码。
- 推理判断: 若在高层类中看到,建议依赖接口并注入实现类(构造函数或setter注入)。
new ConcreteService()
示例
不良设计(高层依赖具体低层模块):
java
class OrderService {
private PaymentService payment = new PaymentService(); // tight coupling
void placeOrder(Order order) {
payment.charge(order.getTotal());
}
}优化设计(依赖抽象;注入实现类):
java
interface PaymentProcessor {
void charge(BigDecimal amount);
}
class OrderService {
private final PaymentProcessor payment;
OrderService(PaymentProcessor payment) {
this.payment = payment;
}
void placeOrder(Order order) {
payment.charge(order.getTotal());
}
}该原则在Spring依赖注入中被大量使用(推荐使用构造函数注入)。
DRY Principle
DRY原则
Definition: Every piece of knowledge should have a single source of truth.
What it achieves (agent context):
- Less duplication — Logic, constants, and validation live in one place; changes propagate automatically.
- Easier maintenance — Fix or evolve behavior in one place instead of hunting duplicates.
- Consistent behavior — Same rule (e.g. "adult = age > 18") applied everywhere.
- Inference: When you see the same condition, formula, or block of code in multiple places, suggest extracting a method, constant, or shared utility.
Example
Bad (same rule repeated):
java
if (user.getAge() > 18) { /* allow */ }
// ...
if (employee.getAge() > 18) { /* allow */ }Better (single source of truth):
java
boolean isAdult(int age) {
return age > 18;
}
// use: if (isAdult(user.getAge())) { ... }定义: 每一份知识都应该有唯一的权威来源。
在Agent场景下的达成目标:
- 减少重复 —— 逻辑、常量和验证逻辑集中在一处;变更可自动同步。
- 更易维护 —— 只需在一处修复或改进行为,无需查找重复代码。
- 行为一致性 —— 同一规则(例如“成年人=年龄>18”)在所有地方保持一致。
- 推理判断: 若在多个地方发现相同的条件、公式或代码块,建议提取为方法、常量或共享工具类。
示例
不良设计(同一规则重复出现):
java
if (user.getAge() > 18) { /* allow */ }
// ...
if (employee.getAge() > 18) { /* allow */ }优化设计(唯一权威来源):
java
boolean isAdult(int age) {
return age > 18;
}
// 使用:if (isAdult(user.getAge())) { ... }KISS Principle
KISS原则
Definition: Design should be as simple as possible (Keep It Simple, Stupid).
What it achieves (agent context):
- Readable code — Others can understand and change it without deep mental load.
- Faster debugging — Fewer moving parts and fewer abstractions to trace.
- Lower complexity — Avoid over-engineering; prefer straightforward conditionals or small methods when they suffice.
- Inference: When code uses heavy abstraction or functional chains where a simple null check or loop would do, suggest the simpler version unless there is a clear benefit (e.g. large streams, reuse).
Example
Overly complex for a simple null check:
java
Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("Unknown");Simpler and clearer when only one level is needed:
java
String city = (user != null && user.getAddress() != null)
? user.getAddress().getCity()
: "Unknown";定义: 设计应尽可能简单(Keep It Simple, Stupid)。
在Agent场景下的达成目标:
- 代码可读性高 —— 他人无需复杂思考即可理解和修改代码。
- 调试更快捷 —— 移动部件更少,需要追踪的抽象层更少。
- 降低复杂度 —— 避免过度设计;若简单的空检查或循环即可满足需求,优先使用简单实现。
- 推理判断: 若代码在简单场景下使用了复杂的抽象或函数链(而简单的空检查或循环即可实现),建议使用更简单的版本,除非有明确的收益(例如处理大型流、复用性)。
示例
针对简单空检查的过度复杂实现:
java
Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.orElse("Unknown");当仅需一层检查时,更简单清晰的实现:
java
String city = (user != null && user.getAddress() != null)
? user.getAddress().getCity()
: "Unknown";Law of Demeter (LoD) / Principle of Least Knowledge
迪米特法则(LoD)/最少知识原则
Definition: A class should only interact with its immediate dependencies (friends), not with their friends.
What it achieves (agent context):
- Reduced coupling — Caller does not depend on the internal structure of nested objects (e.g. ).
order.getCustomer().getAddress().getZipCode() - Better encapsulation — Details of how zip is obtained stay inside the domain (e.g. or a service).
Order - Easier refactoring — If or
Customerstructure changes, only one place (the API that returns zip) needs to change.Address - Inference: When you see chained getters (e.g. ), suggest a single method on the root object or a facade (e.g.
a.getB().getC().getD()).order.getCustomerZipCode()
Example
Bad (chained calls; depends on full path):
java
String zip = order.getCustomer().getAddress().getZipCode();Better (single method on the object you already have):
java
// On Order (or a service that has Order)
String zip = order.getCustomerZipCode();
// implementation: return customer != null && customer.getAddress() != null
// ? customer.getAddress().getZipCode() : null;定义: 一个类应该仅与其直接依赖对象(友元)交互,而非依赖友元的友元。
在Agent场景下的达成目标:
- 降低耦合 —— 调用者不依赖嵌套对象的内部结构(例如)。
order.getCustomer().getAddress().getZipCode() - 更好的封装性 —— 获取邮编的细节保留在领域对象内部(例如或服务类)。
Order - 更易重构 —— 若或
Customer结构变更,仅需修改一处(返回邮编的API)。Address - 推理判断: 若发现链式调用(例如),建议在根对象或外观类中添加单一方法(例如
a.getB().getC().getD())。order.getCustomerZipCode()
示例
不良设计(链式调用;依赖完整路径):
java
String zip = order.getCustomer().getAddress().getZipCode();优化设计(在已有的对象上添加单一方法):
java
// 在Order类(或持有Order的服务类)中
String zip = order.getCustomerZipCode();
// 实现:return customer != null && customer.getAddress() != null
// ? customer.getAddress().getZipCode() : null;Composition Over Inheritance
组合优于继承
Definition: Prefer object composition (has-a) over inheritance (is-a) for reusing behavior.
What it achieves (agent context):
- Flexibility — Behavior can be swapped at runtime; no rigid hierarchy.
- Avoids deep inheritance trees — Fewer fragile base classes and override chains.
- Easier testing — Composed dependencies can be mocked.
- Inference: When you see "X extends Y" only to reuse Y's code (and "X is-a Y" is not a true subtype), suggest holding Y as a field and delegating (composition).
Example
Bad (inheritance for reuse; "Car is-a Engine" is wrong):
java
class Car extends Engine {
void drive() { start(); /* ... */ }
}Better (composition; car has an engine):
java
class Car {
private final Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void drive() {
engine.start();
// ...
}
}定义: 优先使用对象组合(has-a)而非继承(is-a)来复用行为。
在Agent场景下的达成目标:
- 灵活性 —— 行为可在运行时替换;无僵化的继承层次结构。
- 避免深层继承树 —— 减少脆弱的基类和重写链。
- 更易测试 —— 组合的依赖可被模拟。
- 推理判断: 若发现“X extends Y”仅为复用Y的代码(且“X is-a Y”并非真正的子类型关系),建议将Y作为字段持有并委托调用(组合)。
示例
不良设计(为复用代码使用继承;“Car is-a Engine”不成立):
java
class Car extends Engine {
void drive() { start(); /* ... */ }
}优化设计(组合;汽车包含引擎):
java
class Car {
private final Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void drive() {
engine.start();
// ...
}
}Separation of Concerns (SoC)
关注点分离(SoC)
Definition: Divide the system so that each part handles a specific concern (e.g. API, business logic, data access).
What it achieves (agent context):
- Clear architecture — Controllers handle HTTP, services handle rules, repositories handle persistence.
- Easier testing — Each layer can be tested in isolation with mocks.
- Independent evolution — Change API contract or database without rewriting business logic.
- Inference: When business logic appears in controllers or SQL in services, recommend moving it to the appropriate layer (e.g. service for rules, repository for queries).
Example
Typical layering in Spring Boot:
Controller → HTTP, validation, DTO mapping
Service → Business logic, transactions
Repository → Data access, queriesCode-level example:
java
// Controller — only HTTP and delegation
@RestController
class UserController {
private final UserService userService;
UserDto createUser(@RequestBody UserDto dto) {
return userService.createUser(dto);
}
}
// Service — business rules only
@Service
class UserService {
private final UserRepository userRepository;
UserDto createUser(UserDto dto) {
if (userRepository.existsByEmail(dto.getEmail()))
throw new ConflictException("Email already exists");
return map(userRepository.save(toEntity(dto)));
}
}
// Repository — data access only
interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(String email);
}定义: 将系统拆分,使每个部分处理特定的关注点(例如API、业务逻辑、数据访问)。
在Agent场景下的达成目标:
- 清晰的架构 —— 控制器处理HTTP请求,服务类处理业务规则,仓库类处理持久化。
- 更易测试 —— 每个层可通过模拟对象独立测试。
- 独立演进 —— 修改API契约或数据库无需重写业务逻辑。
- 推理判断: 若在控制器中发现业务逻辑,或在服务类中发现SQL语句,建议将其移至合适的层(例如业务逻辑移至服务类,查询语句移至仓库类)。
示例
Spring Boot中的典型分层:
Controller → HTTP处理、验证、DTO映射
Service → 业务逻辑、事务管理
Repository → 数据访问、查询代码级示例:
java
// Controller — 仅处理HTTP请求和委托
@RestController
class UserController {
private final UserService userService;
UserDto createUser(@RequestBody UserDto dto) {
return userService.createUser(dto);
}
}
// Service — 仅处理业务规则
@Service
class UserService {
private final UserRepository userRepository;
UserDto createUser(UserDto dto) {
if (userRepository.existsByEmail(dto.getEmail()))
throw new ConflictException("Email already exists");
return map(userRepository.save(toEntity(dto)));
}
}
// Repository — 仅处理数据访问
interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(String email);
}High Cohesion & Low Coupling
高内聚与低耦合
High Cohesion
高内聚
Definition: A class (or module) should contain closely related responsibilities that work toward one purpose.
What it achieves (agent context): Changes to one feature stay in one place; the class is easier to name, test, and reuse as a unit.
定义: 类(或模块)应包含紧密相关的职责,共同服务于一个目标。
在Agent场景下的达成目标: 某一功能的变更仅影响一处;类的命名、测试和复用都更简单。
Low Coupling
低耦合
Definition: Classes (or modules) should depend minimally on each other, preferably on abstractions.
What it achieves (agent context): Changing one module has fewer ripple effects; systems are easier to refactor and deploy in parts.
Combined inference: When reviewing, prefer modules that do one thing well (high cohesion) and depend on few, stable abstractions (low coupling). Suggest splitting classes that mix unrelated concerns or that depend on many concrete types.
Example
Bad (low cohesion, high coupling — one class does persistence, HTTP, and formatting):
java
class UserHandler {
public String handle(HttpRequest req) {
User u = new User(req.getParam("name"), Integer.parseInt(req.getParam("age")));
try (Connection c = DriverManager.getConnection("jdbc:...")) {
c.createStatement().executeUpdate("INSERT INTO users ...");
}
return "<html><body>Added " + u.getName() + "</body></html>";
}
}Better (separate concerns; each class has one reason to change):
java
class UserController {
private final UserService userService;
ResponseEntity<String> createUser(@RequestBody UserDto dto) {
return ResponseEntity.ok(userService.createUser(dto).getId());
}
}
class UserService {
private final UserRepository userRepository;
User createUser(UserDto dto) {
return userRepository.save(User.from(dto));
}
}
interface UserRepository {
User save(User user);
}定义: 类(或模块)之间的依赖应尽可能少,优先依赖抽象。
在Agent场景下的达成目标: 修改一个模块产生的连锁反应更少;系统更易重构和分部署。
综合推理判断: 评审代码时,优先选择职责单一(高内聚)且依赖少量稳定抽象(低耦合)的模块。若类混合了不相关的关注点,或依赖多个具体类型,建议拆分。
示例
不良设计(低内聚、高耦合——一个类处理持久化、HTTP请求和格式化):
java
class UserHandler {
public String handle(HttpRequest req) {
User u = new User(req.getParam("name"), Integer.parseInt(req.getParam("age")));
try (Connection c = DriverManager.getConnection("jdbc:...")) {
c.createStatement().executeUpdate("INSERT INTO users ...");
}
return "<html><body>Added " + u.getName() + "</body></html>";
}
}优化设计(分离关注点;每个类仅有一个变更原因):
java
class UserController {
private final UserService userService;
ResponseEntity<String> createUser(@RequestBody UserDto dto) {
return ResponseEntity.ok(userService.createUser(dto).getId());
}
}
class UserService {
private final UserRepository userRepository;
User createUser(UserDto dto) {
return userRepository.save(User.from(dto));
}
}
interface UserRepository {
User save(User user);
}Fail Fast Principle
快速失败原则
Definition: Systems should fail immediately when an error or invalid state is detected, rather than continuing and failing later in a harder-to-debug way.
What it achieves (agent context):
- Easier debugging — Failure happens at the point of the bug (e.g. null, invalid argument).
- Prevents hidden bugs — Invalid data is not propagated; no silent wrong results.
- Inference: Recommend validating inputs at boundaries (e.g. controller, public API) and using assertions or for invariants; avoid swallowing exceptions or returning sentinel values when a clear failure is more appropriate.
requireNonNull
Example
Validate early; fail fast:
java
public User createUser(String name, int age) {
Objects.requireNonNull(name, "name must not be null");
if (age < 0 || age > 150)
throw new IllegalArgumentException("Invalid age: " + age);
return new User(name, age);
}定义: 系统应在检测到错误或无效状态时立即失败,而非继续运行并在后续出现更难调试的问题。
在Agent场景下的达成目标:
- 更易调试 —— 错误发生在问题出现的位置(例如空值、无效参数)。
- 防止隐藏bug —— 无效数据不会被传播;不会出现静默的错误结果。
- 推理判断: 建议在边界处(例如控制器、公共API)验证输入,对不变量使用断言或;当明确需要失败时,避免吞掉异常或返回哨兵值。
requireNonNull
示例
提前验证;快速失败:
java
public User createUser(String name, int age) {
Objects.requireNonNull(name, "name must not be null");
if (age < 0 || age > 150)
throw new IllegalArgumentException("Invalid age: " + age);
return new User(name, age);
}Immutability Principle
不可变性原则
Definition: Objects should not change state after creation; all state is set in the constructor and never modified.
What it achieves (agent context):
- Thread safety — Immutable objects can be shared without synchronization.
- Predictable behavior — No hidden changes; same reference always represents same value.
- Easier concurrency and caching — Safe to cache and pass across threads.
- Inference: When you see setters or mutable fields on value-like objects (e.g. DTOs, domain values), suggest immutable alternatives (records, final fields, copy-on-write if needed).
Example
Immutable value with Java record:
java
public record User(String name, int age) {
// Compact constructor for validation
public User {
Objects.requireNonNull(name);
if (age < 0) throw new IllegalArgumentException("age must be non-negative");
}
}Traditional immutable class:
java
public final class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = Objects.requireNonNull(name);
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
// No setters
}定义: 对象在创建后不应改变状态;所有状态在构造函数中设置,且永不修改。
在Agent场景下的达成目标:
- 线程安全 —— 不可变对象可在无同步的情况下共享。
- 行为可预测 —— 无隐藏的状态变更;同一引用始终代表相同的值。
- 更易并发和缓存 —— 可安全地缓存并在线程间传递。
- 推理判断: 若在值类型对象(例如DTO、领域值对象)上发现setter或可变字段,建议使用不可变替代方案(record、final字段,必要时使用写时复制)。
示例
使用Java record实现的不可变值对象:
java
public record User(String name, int age) {
// 紧凑构造函数用于验证
public User {
Objects.requireNonNull(name);
if (age < 0) throw new IllegalArgumentException("age must be non-negative");
}
}传统不可变类:
java
public final class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = Objects.requireNonNull(name);
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
// 无setter
}Required Output Format
要求输出格式
When this skill is invoked for a design or code review, the response must exactly follow one of the two templates below:
当本技能被用于设计或代码评审时,响应必须严格遵循以下两个模板之一:
Template A (any findings)
模板A(存在问题)
markdown
undefinedmarkdown
undefinedDesign Review Summary
设计评审总结
Found <X> critical issues need to be fixed:
发现 <X> 个严重问题需要修复:
🔴 Critical (Must Fix)
🔴 严重问题(必须修复)
1. <brief description of the issue>
1. <问题简要描述>
FilePath: <path> line <line>
<relevant code snippet or pointer>
文件路径:<路径> 行 <行号>
<相关代码片段或指向>
Explanation
说明
<detailed explanation and references of the issue>
<问题的详细说明和参考>
Suggested Fix
建议修复方案
- <brief description of suggested fix>
- <code example> (optional, omit if not applicable)
... (repeat for each critical issue) ...
Found <Y> suggestions for improvement:
- <修复建议简要描述>
- <代码示例>(可选,不适用则省略)
...(每个严重问题重复上述结构)...
发现 <Y> 个改进建议:
🟡 Suggestions (Should Consider)
🟡 改进建议(建议考虑)
1. <brief description of the suggestion>
1. <建议简要描述>
FilePath: <path> line <line>
<relevant code snippet or pointer>
文件路径:<路径> 行 <行号>
<相关代码片段或指向>
Explanation
说明
<detailed explanation and references of the suggestion>
<建议的详细说明和参考>
Suggested Fix
建议修复方案
- <brief description of suggested fix>
- <code example> (optional, omit if not applicable)
... (repeat for each suggestion) ...
- <修复建议简要描述>
- <代码示例>(可选,不适用则省略)
...(每个改进建议重复上述结构)...
✅ What's Good
✅ 优点
- <Positive feedback on good patterns>
- If there are no critical issues or suggestions or good points, just omit that section.
- If the issue number is more than 10, summarize as "Found 10+ critical issues/suggestions" and only output the first 10 items.- <对良好模式的正面反馈>
- 若无严重问题、改进建议或优点,可省略对应章节。
- 若问题数量超过10个,总结为“发现10+个严重问题/改进建议”,并仅输出前10个。Template B (no issues)
模板B(无问题)
markdown
undefinedmarkdown
undefinedDesign Review Summary
设计评审总结
✅ No issues found.
---✅ 未发现问题。
---Knowledge Reference
知识参考
Java 17, Spring Boot 3.x, JUnit 5, Mockito, Maven/Gradle
Java 17, Spring Boot 3.x, JUnit 5, Mockito, Maven/Gradle