設計指引範本

Prompt 目標

指導 AI 進行軟體設計,建立符合設計原則、易於維護且可擴展的軟體設計。

角色設定

你是一位資深軟體設計師,具備豐富的軟體設計經驗,熟悉設計模式、SOLID 原則和軟體工程最佳實務。

任務描述

請協助我完成 {專案名稱} 的軟體設計工作。

專案設計背景

  • 專案名稱: {填入專案名稱}
  • 設計範圍: {填入設計範圍,如:核心模組、特定功能}
  • 技術棧: {填入使用的技術棧}
  • 設計約束: {填入設計限制和約束}
  • 品質要求: {填入品質屬性要求}

設計要求

請按照以下結構進行設計:

1. 領域建模

  • 核心領域識別
  • 實體和值物件設計
  • 聚合設計
  • 領域服務設計

2. 架構設計

  • 分層架構設計
  • 模組劃分
  • 依賴關係設計
  • 介面設計

3. 詳細設計

  • 類別設計
  • 方法設計
  • 資料結構設計
  • 演算法設計

4. 設計模式應用

  • 創建型模式
  • 結構型模式
  • 行為型模式
  • 架構模式

5. 設計原則遵循

  • SOLID 原則
  • DRY 原則
  • KISS 原則
  • YAGNI 原則

輸出格式

# {專案名稱} 軟體設計文件

## 1. 設計概述

### 1.1 設計目標
**主要目標:**
- {目標1}
- {目標2}
- {目標3}

**品質屬性:**
- **可維護性:** {可維護性要求}
- **可擴展性:** {可擴展性要求}
- **可重用性:** {可重用性要求}
- **可測試性:** {可測試性要求}

### 1.2 設計約束
**技術約束:**
- 程式語言: {程式語言}
- 框架: {使用的框架}
- 資料庫: {資料庫類型}
- 部署環境: {部署環境}

**業務約束:**
- 效能要求: {效能指標}
- 安全要求: {安全等級}
- 相容性要求: {相容性需求}

## 2. 領域建模

### 2.1 領域識別

#### 核心領域 (Core Domain)
**領域名稱:** {核心業務領域}
**複雜度:** 高
**業務價值:** 高
**描述:** {領域描述}

**主要概念:**
- {概念1}: {概念描述}
- {概念2}: {概念描述}
- {概念3}: {概念描述}

#### 支援領域 (Supporting Domain)
**領域名稱:** {支援領域}
**複雜度:** 中
**業務價值:** 中
**描述:** {領域描述}

#### 通用領域 (Generic Domain)
**領域名稱:** {通用領域}
**複雜度:** 低
**業務價值:** 低
**解決方案:** {現成解決方案或第三方服務}

### 2.2 實體設計 (Entity)

#### 實體: {實體名稱}
```java
/**
 * {實體描述}
 * 不變量: {業務規則和約束}
 */
public class {實體名稱} {
    
    // 唯一識別碼
    private {ID類型} id;
    
    // 業務屬性
    private {屬性類型} {屬性名稱};
    
    // 建構子
    public {實體名稱}({參數列表}) {
        // 驗證業務規則
        validateBusinessRules();
        this.{屬性} = {值};
    }
    
    // 業務方法
    public {返回類型} {業務方法名稱}({參數列表}) {
        // 業務邏輯實作
        return {結果};
    }
    
    // 不變量驗證
    private void validateBusinessRules() {
        if ({條件}) {
            throw new {例外類型}("{錯誤訊息}");
        }
    }
    
    // equals 和 hashCode 基於 ID
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof {實體名稱})) return false;
        {實體名稱} other = ({實體名稱}) obj;
        return Objects.equals(id, other.id);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

2.3 值物件設計 (Value Object)

值物件: {值物件名稱}

/**
 * {值物件描述}
 * 特性: 不可變、值相等、自驗證
 */
public final class {值物件名稱} {
    
    private final {屬性類型} {屬性名稱};
    
    public {值物件名稱}({參數類型} {參數名稱}) {
        validate({參數名稱});
        this.{屬性名稱} = {參數名稱};
    }
    
    public {屬性類型} get{屬性名稱}() {
        return {屬性名稱};
    }
    
    private void validate({參數類型} value) {
        if ({驗證條件}) {
            throw new IllegalArgumentException("{錯誤訊息}");
        }
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof {值物件名稱})) return false;
        {值物件名稱} other = ({值物件名稱}) obj;
        return Objects.equals({屬性名稱}, other.{屬性名稱});
    }
    
    @Override
    public int hashCode() {
        return Objects.hash({屬性名稱});
    }
    
    @Override
    public String toString() {
        return "{值物件名稱}{" + "{屬性名稱}=" + {屬性名稱} + '}';
    }
}

2.4 聚合設計 (Aggregate)

聚合: {聚合名稱}

/**
 * {聚合描述}
 * 聚合根: {聚合根實體}
 * 邊界: {聚合邊界說明}
 */
public class {聚合名稱} {
    
    // 聚合根
    private {實體類型} {聚合根};
    
    // 聚合內實體
    private List<{實體類型}> {內部實體列表};
    
    // 聚合建構
    public {聚合名稱}({參數列表}) {
        this.{聚合根} = new {實體類型}({參數});
        this.{內部實體列表} = new ArrayList<>();
    }
    
    // 業務操作
    public void {業務操作名稱}({參數列表}) {
        // 驗證聚合不變量
        validateAggregateInvariants();
        
        // 執行業務邏輯
        {聚合根}.{業務方法}({參數});
        
        // 發布領域事件
        publishDomainEvent(new {事件類型}({事件資料}));
    }
    
    // 聚合不變量驗證
    private void validateAggregateInvariants() {
        if ({不變量條件}) {
            throw new {例外類型}("{違反不變量訊息}");
        }
    }
    
    // 取得聚合根 ID
    public {ID類型} getId() {
        return {聚合根}.getId();
    }
}

2.5 領域服務設計

領域服務: {服務名稱}

/**
 * {服務描述}
 * 使用場景: {使用場景說明}
 */
@DomainService
public class {服務名稱} {
    
    private final {依賴類型} {依賴名稱};
    
    public {服務名稱}({依賴類型} {依賴名稱}) {
        this.{依賴名稱} = {依賴名稱};
    }
    
    /**
     * {業務操作描述}
     * @param {參數} {參數描述}
     * @return {返回值描述}
     */
    public {返回類型} {業務操作}({參數列表}) {
        // 前置條件檢查
        validatePreconditions({參數});
        
        // 業務邏輯執行
        {返回類型} result = executeBusinessLogic({參數});
        
        // 後置條件檢查
        validatePostconditions(result);
        
        return result;
    }
}

3. 架構設計

3.1 分層架構

四層架構設計

┌─────────────────────────────────────┐
│           展示層 (Presentation)       │
├─────────────────────────────────────┤
│           應用層 (Application)        │
├─────────────────────────────────────┤
│            領域層 (Domain)           │
├─────────────────────────────────────┤
│           基礎設施層 (Infrastructure) │
└─────────────────────────────────────┘

展示層 (Presentation Layer)

職責:

  • 處理使用者介面邏輯
  • 請求路由和參數驗證
  • 回應格式化
  • 錯誤處理和回應

組件設計:

@RestController
@RequestMapping("/api/v1/{資源}")
public class {資源}Controller {
    
    private final {應用服務} {服務};
    
    @GetMapping("/{id}")
    public ResponseEntity<{DTO}> get{資源}(@PathVariable String id) {
        {DTO} result = {服務}.get{資源}(id);
        return ResponseEntity.ok(result);
    }
    
    @PostMapping
    public ResponseEntity<{DTO}> create{資源}(@Valid @RequestBody {CreateDTO} request) {
        {DTO} result = {服務}.create{資源}(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(result);
    }
}

應用層 (Application Layer)

職責:

  • 協調領域物件執行業務用例
  • 管理事務邊界
  • 安全檢查和授權
  • 資料轉換和映射

組件設計:

@ApplicationService
@Transactional
public class {資源}ApplicationService {
    
    private final {資源}Repository {資源儲存庫};
    private final {領域服務} {領域服務};
    private final {外部服務} {外部服務};
    
    public {DTO} create{資源}({CreateDTO} request) {
        // 1. 輸入驗證
        validateInput(request);
        
        // 2. 業務規則檢查
        checkBusinessRules(request);
        
        // 3. 建立領域物件
        {聚合} {聚合實例} = {聚合}.create(request.to{聚合}());
        
        // 4. 儲存聚合
        {聚合實例} = {資源儲存庫}.save({聚合實例});
        
        // 5. 發布整合事件
        publishIntegrationEvent(new {事件}({聚合實例}.getId()));
        
        // 6. 回傳結果
        return {DTO}.from({聚合實例});
    }
}

領域層 (Domain Layer)

職責:

  • 實作核心業務邏輯
  • 定義業務規則和不變量
  • 管理領域事件
  • 提供領域服務

組件組織:

domain/
├── model/           # 領域模型
│   ├── {實體}.java
│   ├── {值物件}.java
│   └── {聚合}.java
├── service/         # 領域服務
│   └── {領域服務}.java
├── repository/      # 儲存庫介面
│   └── {儲存庫介面}.java
├── event/          # 領域事件
│   └── {領域事件}.java
└── exception/      # 領域例外
    └── {領域例外}.java

基礎設施層 (Infrastructure Layer)

職責:

  • 實作技術關注點
  • 提供持久化實作
  • 外部服務整合
  • 框架配置

組件設計:

@Repository
public class {資源}RepositoryImpl implements {資源}Repository {
    
    private final {JPA實體}Repository jpaRepository;
    private final {資源}Mapper mapper;
    
    @Override
    public {聚合} save({聚合} {聚合實例}) {
        {JPA實體} entity = mapper.toEntity({聚合實例});
        entity = jpaRepository.save(entity);
        return mapper.toDomain(entity);
    }
    
    @Override
    public Optional<{聚合}> findById({ID類型} id) {
        return jpaRepository.findById(id)
            .map(mapper::toDomain);
    }
}

3.2 模組劃分

模組結構設計

src/main/java/
├── {專案包名}/
│   ├── {核心模組}/           # 核心業務模組
│   │   ├── domain/
│   │   ├── application/
│   │   ├── infrastructure/
│   │   └── presentation/
│   ├── {支援模組}/           # 支援業務模組
│   │   ├── domain/
│   │   ├── application/
│   │   └── infrastructure/
│   ├── shared/             # 共用組件
│   │   ├── kernel/         # 共用核心
│   │   ├── infrastructure/ # 共用基礎設施
│   │   └── application/    # 共用應用服務
│   └── config/             # 配置類

模組依賴規則

/**
 * 模組依賴矩陣
 * ✓ = 允許依賴
 * ✗ = 禁止依賴
 */
//                    核心模組  支援模組  共用模組
// 核心模組              ✗      ✗       ✓
// 支援模組              ✗      ✗       ✓  
// 共用模組              ✗      ✗       ✗

3.3 介面設計

介面隔離原則應用

// 細粒度介面設計
public interface {資源}Reader {
    Optional<{資源}> findById({ID類型} id);
    List<{資源}> findAll();
}

public interface {資源}Writer {
    {資源} save({資源} {資源實例});
    void delete({ID類型} id);
}

public interface {資源}Repository extends {資源}Reader, {資源}Writer {
    // 複合介面,組合讀寫能力
}

介面穩定性設計

@API(status = API.Status.STABLE)
public interface {穩定介面} {
    // 穩定的公開 API,版本間保持相容
}

@API(status = API.Status.EXPERIMENTAL)
public interface {實驗性介面} {
    // 實驗性 API,可能在未來版本變更
}

@API(status = API.Status.DEPRECATED)
public interface {已棄用介面} {
    // 已棄用 API,將在未來版本移除
}

4. 詳細設計

4.1 類別設計

類別設計原則

單一職責原則 (SRP):

// 良好設計 - 職責明確
public class {資源}Validator {
    public ValidationResult validate({資源} {資源實例}) {
        // 只負責驗證邏輯
    }
}

public class {資源}Formatter {
    public String format({資源} {資源實例}) {
        // 只負責格式化
    }
}

開放封閉原則 (OCP):

// 抽象基類
public abstract class {處理器} {
    public final {結果} process({輸入} input) {
        {中間結果} intermediate = preProcess(input);
        {結果} result = doProcess(intermediate);
        return postProcess(result);
    }
    
    protected abstract {中間結果} preProcess({輸入} input);
    protected abstract {結果} doProcess({中間結果} intermediate);
    protected abstract {結果} postProcess({結果} result);
}

// 具體實作 - 擴展而非修改
public class {具體處理器} extends {處理器} {
    // 實作抽象方法
}

類別關係設計

// 組合優於繼承
public class {服務類} {
    
    // 通過組合使用其他類的功能
    private final {驗證器} validator;
    private final {轉換器} converter;
    private final {儲存庫} repository;
    
    public {服務類}({驗證器} validator, {轉換器} converter, {儲存庫} repository) {
        this.validator = validator;
        this.converter = converter;
        this.repository = repository;
    }
    
    public {結果} process({輸入} input) {
        // 組合各組件完成功能
        validator.validate(input);
        {中間結果} converted = converter.convert(input);
        return repository.save(converted);
    }
}

4.2 方法設計

方法簽名設計

/**
 * 方法命名和參數設計指引
 */
public class {服務類} {
    
    // 動詞+名詞命名,參數類型明確
    public {返回類型} calculate{業務概念}({輸入類型} input, {配置類型} config) {
        // 方法實作
    }
    
    // 布林方法使用 is/has/can 前綴
    public boolean isValid({對象類型} object) {
        return {驗證邏輯};
    }
    
    // 查詢方法使用 find/get 前綴
    public Optional<{對象類型}> findBy{條件}({條件類型} criteria) {
        return {查詢邏輯};
    }
    
    // 建議方法參數不超過3個,否則使用參數對象
    public {結果} complexOperation({參數對象} parameters) {
        // 複雜操作使用參數對象
    }
}

錯誤處理設計

public class {服務類} {
    
    // 使用特定例外類型
    public {結果} riskyOperation({輸入} input) throws {業務例外}, {技術例外} {
        try {
            // 前置條件檢查
            validatePreconditions(input);
            
            // 核心邏輯
            {結果} result = performOperation(input);
            
            // 後置條件檢查
            validatePostconditions(result);
            
            return result;
            
        } catch ({特定例外} e) {
            // 特定錯誤處理
            throw new {業務例外}("業務錯誤描述", e);
        } catch (Exception e) {
            // 通用錯誤處理
            throw new {技術例外}("系統錯誤", e);
        }
    }
}

4.3 資料結構設計

不可變物件設計

public final class {不可變類} {
    
    private final {屬性類型} {屬性1};
    private final List<{元素類型}> {屬性2};
    
    public {不可變類}({屬性類型} {屬性1}, List<{元素類型}> {屬性2}) {
        this.{屬性1} = {屬性1};
        this.{屬性2} = Collections.unmodifiableList(new ArrayList<>({屬性2}));
    }
    
    public {屬性類型} get{屬性1}() {
        return {屬性1};
    }
    
    public List<{元素類型}> get{屬性2}() {
        return {屬性2}; // 已經是不可變的
    }
    
    // Builder 模式用於複雜對象建構
    public static class Builder {
        private {屬性類型} {屬性1};
        private List<{元素類型}> {屬性2} = new ArrayList<>();
        
        public Builder {屬性1}({屬性類型} {屬性1}) {
            this.{屬性1} = {屬性1};
            return this;
        }
        
        public Builder add{元素類型}({元素類型} item) {
            this.{屬性2}.add(item);
            return this;
        }
        
        public {不可變類} build() {
            return new {不可變類}({屬性1}, {屬性2});
        }
    }
}

集合使用指引

public class {集合使用示例} {
    
    // 優先使用介面類型
    private final List<{元素}> items = new ArrayList<>();
    private final Map<{鍵}, {值}> cache = new HashMap<>();
    private final Set<{元素}> uniqueItems = new HashSet<>();
    
    // 防禦性複製
    public List<{元素}> getItems() {
        return new ArrayList<>(items);
    }
    
    // 空集合處理
    public List<{元素}> findItems({條件} criteria) {
        List<{元素}> result = performSearch(criteria);
        return result != null ? result : Collections.emptyList();
    }
}

5. 設計模式應用

5.1 創建型模式

工廠方法模式

// 抽象工廠
public abstract class {產品}Factory {
    
    public {產品} create({配置} config) {
        {產品} product = createProduct(config);
        configureProduct(product, config);
        return product;
    }
    
    protected abstract {產品} createProduct({配置} config);
    
    private void configureProduct({產品} product, {配置} config) {
        // 通用配置邏輯
    }
}

// 具體工廠
public class {具體產品}Factory extends {產品}Factory {
    
    @Override
    protected {產品} createProduct({配置} config) {
        return new {具體產品}(config);
    }
}

建造者模式

public class {複雜對象} {
    
    private final {必要屬性} {屬性1};
    private final {可選屬性} {屬性2};
    private final {可選屬性} {屬性3};
    
    private {複雜對象}(Builder builder) {
        this.{屬性1} = builder.{屬性1};
        this.{屬性2} = builder.{屬性2};
        this.{屬性3} = builder.{屬性3};
    }
    
    public static class Builder {
        // 必要參數
        private final {必要屬性} {屬性1};
        
        // 可選參數 - 初始化為預設值
        private {可選屬性} {屬性2} = {預設值};
        private {可選屬性} {屬性3} = {預設值};
        
        public Builder({必要屬性} {屬性1}) {
            this.{屬性1} = {屬性1};
        }
        
        public Builder {屬性2}({可選屬性} {屬性2}) {
            this.{屬性2} = {屬性2};
            return this;
        }
        
        public Builder {屬性3}({可選屬性} {屬性3}) {
            this.{屬性3} = {屬性3};
            return this;
        }
        
        public {複雜對象} build() {
            return new {複雜對象}(this);
        }
    }
}

5.2 結構型模式

介面卡模式

// 目標介面
public interface {目標介面} {
    {結果} operation({輸入} input);
}

// 需要適配的類
public class {被適配類} {
    public {不同結果} differentOperation({不同輸入} input) {
        // 原有邏輯
    }
}

// 介面卡
public class {介面卡} implements {目標介面} {
    
    private final {被適配類} adaptee;
    
    public {介面卡}({被適配類} adaptee) {
        this.adaptee = adaptee;
    }
    
    @Override
    public {結果} operation({輸入} input) {
        // 轉換輸入格式
        {不同輸入} adaptedInput = convertInput(input);
        
        // 呼叫被適配類的方法
        {不同結果} adaptedResult = adaptee.differentOperation(adaptedInput);
        
        // 轉換輸出格式
        return convertOutput(adaptedResult);
    }
}

裝飾者模式

// 基礎介面
public interface {組件} {
    {結果} operation();
}

// 具體組件
public class {具體組件} implements {組件} {
    @Override
    public {結果} operation() {
        // 基礎功能實作
    }
}

// 抽象裝飾者
public abstract class {裝飾者} implements {組件} {
    
    protected final {組件} component;
    
    public {裝飾者}({組件} component) {
        this.component = component;
    }
    
    @Override
    public {結果} operation() {
        return component.operation();
    }
}

// 具體裝飾者
public class {具體裝飾者} extends {裝飾者} {
    
    public {具體裝飾者}({組件} component) {
        super(component);
    }
    
    @Override
    public {結果} operation() {
        // 前置處理
        preProcess();
        
        // 呼叫原有功能
        {結果} result = super.operation();
        
        // 後置處理
        postProcess(result);
        
        return result;
    }
}

5.3 行為型模式

策略模式

// 策略介面
public interface {策略} {
    {結果} execute({輸入} input);
}

// 具體策略
public class {具體策略A} implements {策略} {
    @Override
    public {結果} execute({輸入} input) {
        // 策略A的實作
    }
}

public class {具體策略B} implements {策略} {
    @Override
    public {結果} execute({輸入} input) {
        // 策略B的實作
    }
}

// 上下文
public class {上下文} {
    
    private {策略} strategy;
    
    public {上下文}({策略} strategy) {
        this.strategy = strategy;
    }
    
    public void setStrategy({策略} strategy) {
        this.strategy = strategy;
    }
    
    public {結果} performOperation({輸入} input) {
        return strategy.execute(input);
    }
}

觀察者模式

// 事件
public class {事件} {
    private final {事件資料} data;
    private final LocalDateTime timestamp;
    
    public {事件}({事件資料} data) {
        this.data = data;
        this.timestamp = LocalDateTime.now();
    }
}

// 觀察者介面
public interface {觀察者} {
    void handle({事件} event);
}

// 主題
public class {主題} {
    
    private final List<{觀察者}> observers = new ArrayList<>();
    
    public void addObserver({觀察者} observer) {
        observers.add(observer);
    }
    
    public void removeObserver({觀察者} observer) {
        observers.remove(observer);
    }
    
    protected void notifyObservers({事件} event) {
        for ({觀察者} observer : observers) {
            try {
                observer.handle(event);
            } catch (Exception e) {
                // 記錄錯誤,但不影響其他觀察者
                logError("Observer error", e);
            }
        }
    }
    
    public void performAction({輸入} input) {
        // 執行業務邏輯
        {結果} result = executeBusinessLogic(input);
        
        // 通知觀察者
        notifyObservers(new {事件}(result));
    }
}

6. 設計原則遵循

6.1 SOLID 原則

單一職責原則 (SRP)

// 違反 SRP - 一個類有多個變更理由
public class BadUserService {
    public void createUser(User user) { /* ... */ }
    public void sendEmail(String email) { /* ... */ }
    public String formatUserReport(User user) { /* ... */ }
}

// 遵循 SRP - 每個類只有一個職責
public class UserService {
    public void createUser(User user) { /* ... */ }
}

public class EmailService {
    public void sendEmail(String email) { /* ... */ }
}

public class UserReportFormatter {
    public String formatUserReport(User user) { /* ... */ }
}

開放封閉原則 (OCP)

// 遵循 OCP - 對擴展開放,對修改封閉
public interface PaymentProcessor {
    PaymentResult process(Payment payment);
}

public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public PaymentResult process(Payment payment) {
        // 信用卡處理邏輯
    }
}

public class PayPalProcessor implements PaymentProcessor {
    @Override
    public PaymentResult process(Payment payment) {
        // PayPal 處理邏輯
    }
}

// 新增支付方式無需修改現有程式碼
public class BankTransferProcessor implements PaymentProcessor {
    @Override
    public PaymentResult process(Payment payment) {
        // 銀行轉帳處理邏輯
    }
}

里氏替換原則 (LSP)

// 遵循 LSP - 子類可以替換父類而不影響程式正確性
public abstract class Bird {
    public abstract void move();
}

public class FlyingBird extends Bird {
    @Override
    public void move() {
        fly();
    }
    
    protected void fly() {
        // 飛行邏輯
    }
}

public class WalkingBird extends Bird {
    @Override
    public void move() {
        walk();
    }
    
    protected void walk() {
        // 行走邏輯
    }
}

介面隔離原則 (ISP)

// 違反 ISP - 大而全的介面
public interface BadWorker {
    void work();
    void eat();
    void sleep();
}

// 遵循 ISP - 細粒度介面
public interface Worker {
    void work();
}

public interface Eater {
    void eat();
}

public interface Sleeper {
    void sleep();
}

// 實作類只實作需要的介面
public class Human implements Worker, Eater, Sleeper {
    @Override
    public void work() { /* ... */ }
    
    @Override
    public void eat() { /* ... */ }
    
    @Override
    public void sleep() { /* ... */ }
}

public class Robot implements Worker {
    @Override
    public void work() { /* ... */ }
}

依賴反轉原則 (DIP)

// 高層模組不應依賴低層模組,都應依賴抽象
public interface NotificationService {
    void send(String message, String recipient);
}

public class EmailNotificationService implements NotificationService {
    @Override
    public void send(String message, String recipient) {
        // 郵件發送實作
    }
}

public class SmsNotificationService implements NotificationService {
    @Override
    public void send(String message, String recipient) {
        // 簡訊發送實作
    }
}

// 高層模組依賴抽象
public class OrderService {
    
    private final NotificationService notificationService;
    
    public OrderService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
    
    public void processOrder(Order order) {
        // 處理訂單
        processOrderLogic(order);
        
        // 發送通知 - 不依賴具體實作
        notificationService.send("訂單已處理", order.getCustomerEmail());
    }
}

6.2 其他設計原則

DRY 原則 (Don’t Repeat Yourself)

// 避免重複 - 提取通用邏輯
public abstract class BaseService<T, ID> {
    
    protected final Repository<T, ID> repository;
    
    public BaseService(Repository<T, ID> repository) {
        this.repository = repository;
    }
    
    public T save(T entity) {
        validate(entity);
        return repository.save(entity);
    }
    
    public Optional<T> findById(ID id) {
        return repository.findById(id);
    }
    
    protected abstract void validate(T entity);
}

// 具體服務繼承通用邏輯
public class UserService extends BaseService<User, Long> {
    
    public UserService(UserRepository repository) {
        super(repository);
    }
    
    @Override
    protected void validate(User user) {
        // 使用者特定驗證邏輯
    }
}

KISS 原則 (Keep It Simple, Stupid)

// 簡單直接的實作
public class TaxCalculator {
    
    public BigDecimal calculateTax(BigDecimal amount, TaxRate rate) {
        return amount.multiply(rate.getValue());
    }
}

// 避免過度複雜的設計
public class SimpleValidator {
    
    public boolean isValidEmail(String email) {
        return email != null && 
               email.contains("@") && 
               email.contains(".");
    }
}

YAGNI 原則 (You Aren’t Gonna Need It)

// 只實作當前需要的功能,不預先建置可能需要的功能
public class User {
    
    private String id;
    private String name;
    private String email;
    
    // 只包含目前需要的屬性和方法
    // 不要因為"可能會需要"而新增額外功能
    
    public User(String id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
    
    // 基本的 getter 方法
    public String getId() { return id; }
    public String getName() { return name; }
    public String getEmail() { return email; }
}

7. 設計驗證和測試

7.1 設計可測試性

依賴注入設計

public class OrderService {
    
    private final PaymentService paymentService;
    private final InventoryService inventoryService;
    private final NotificationService notificationService;
    
    // 建構子注入 - 便於測試
    public OrderService(
            PaymentService paymentService,
            InventoryService inventoryService,
            NotificationService notificationService) {
        this.paymentService = paymentService;
        this.inventoryService = inventoryService;
        this.notificationService = notificationService;
    }
    
    public OrderResult processOrder(Order order) {
        // 業務邏輯 - 容易進行單元測試
        if (!inventoryService.isAvailable(order.getItems())) {
            return OrderResult.insufficientInventory();
        }
        
        PaymentResult payment = paymentService.processPayment(order.getPayment());
        if (!payment.isSuccessful()) {
            return OrderResult.paymentFailed();
        }
        
        inventoryService.reserveItems(order.getItems());
        notificationService.sendConfirmation(order.getCustomer());
        
        return OrderResult.success();
    }
}

測試案例設計

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    
    @Mock
    private PaymentService paymentService;
    
    @Mock
    private InventoryService inventoryService;
    
    @Mock
    private NotificationService notificationService;
    
    @InjectMocks
    private OrderService orderService;
    
    @Test
    void shouldProcessOrderSuccessfully() {
        // Given
        Order order = createTestOrder();
        when(inventoryService.isAvailable(order.getItems())).thenReturn(true);
        when(paymentService.processPayment(order.getPayment()))
            .thenReturn(PaymentResult.success());
        
        // When
        OrderResult result = orderService.processOrder(order);
        
        // Then
        assertThat(result.isSuccessful()).isTrue();
        verify(inventoryService).reserveItems(order.getItems());
        verify(notificationService).sendConfirmation(order.getCustomer());
    }
    
    @Test
    void shouldFailWhenInventoryInsufficient() {
        // Given
        Order order = createTestOrder();
        when(inventoryService.isAvailable(order.getItems())).thenReturn(false);
        
        // When
        OrderResult result = orderService.processOrder(order);
        
        // Then
        assertThat(result.isSuccessful()).isFalse();
        assertThat(result.getFailureReason()).isEqualTo("INSUFFICIENT_INVENTORY");
        verify(paymentService, never()).processPayment(any());
    }
}

7.2 設計審查清單

程式碼審查重點

## 設計審查清單

### 1. 職責分離
- [ ] 每個類都有明確且單一的職責
- [ ] 方法長度適中(建議不超過20行)
- [ ] 類別大小合理(建議不超過200行)

### 2. 依賴管理
- [ ] 使用依賴注入而非直接建立對象
- [ ] 依賴介面而非具體實作
- [ ] 避免循環依賴

### 3. 錯誤處理
- [ ] 適當的例外處理策略
- [ ] 使用特定的例外類型
- [ ] 例外訊息具有診斷價值

### 4. 效能考量
- [ ] 避免不必要的物件建立
- [ ] 適當使用快取
- [ ] 資料庫查詢最佳化

### 5. 安全性
- [ ] 輸入驗證
- [ ] 輸出編碼
- [ ] 存取控制

### 6. 可維護性
- [ ] 程式碼可讀性良好
- [ ] 適當的註解和文件
- [ ] 遵循編碼規範

8. 工具和資源

8.1 設計工具

  • UML 建模: PlantUML, Enterprise Architect
  • 程式碼分析: SonarQube, SpotBugs
  • 依賴分析: JDepend, ArchUnit
  • 重構工具: IntelliJ IDEA, Eclipse

8.2 設計資源

  • 設計模式: Gang of Four 設計模式
  • 領域驅動設計: Eric Evans DDD
  • 企業應用架構: Martin Fowler PoEAA
  • 重構技術: Martin Fowler Refactoring

注意事項

  1. 設計應該根據實際需求演進,避免過度設計
  2. 保持設計的簡潔性和可理解性
  3. 重視程式碼的可讀性和可維護性
  4. 定期重構以保持設計的清潔
  5. 使用自動化測試保證設計變更的安全性
  6. 記錄重要的設計決策和變更理由