| 關係 | 關鍵字 | 語意 | 耦合度 |
|---|---|---|---|
| 繼承 | extends | Is-A(是一種),子類擁有父類所有行為與狀態 | 強(白盒復用,破壞封裝) |
| 組合 | 成員變數 | Has-A(擁有),類別委託給內部物件完成功能 | 弱(黑盒復用,保持封裝) |
Animal → Cat、PaymentStrategy → AlipayPayment。id、createTime),子類繼承。建議:子類顯式重寫或改用組合(BaseEntity 作為嵌入欄位)。// 父類定義通用欄位
public class BaseModel {
private Long id;
private Date createTime;
private Date updateTime;
// getter/setter...
}
// 所有實體強制繼承
public class User extends BaseModel { /* ... */ }
public class Order extends BaseModel { /* ... */ }
public class Product extends BaseModel { /* ... */ }
orderNo,用戶需要 email,強行統一反而增加無用欄位。當你想查找 User.id 的使用位置:
BaseModel.id 所有子類的引用位置(Order.id、Product.id...)根因:繼承將「偶然相同」的結構強行綁定為「必然相同」,違反介面隔離原則與單一職責原則。
// 獨立的基礎資料類(可為 record 或 Lombok @Data)
public class BaseEntity {
private Long id;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// getter/setter...
}
// 實體組合嵌入
@Entity
public class User {
@EmbeddedId // 或 @Embedded + 獨立主鍵
private BaseEntity base;
private String username;
private String email;
// 業務欄位...
}
public interface Identifiable<ID> {
ID getId();
void setId(ID id);
}
public interface Auditable {
LocalDateTime getCreatedAt();
LocalDateTime getUpdatedAt();
}
// 實體實作多個介面,各司其職
public class Order implements Identifiable<Long>, Auditable {
private Long id;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private String orderNo;
// ...
}
優勢:編譯期約束、無強制繼承層級、支援多實作、查找引用精確。
若繼承關係通過「子類型可替換父類型且不破壞行為」,則合理。測試:
經典違規:Square extends Rectangle(設寬高邏輯衝突)、Penguin extends Bird(飛行行為缺失)。
記住:繼承是強關係,組合是弱關係;弱關係系統更靈活、更穩健。