组合优于继承:构建灵活可扩展的系统架构
在软件设计中,继承虽然强大,但过度使用往往会导致代码结构变得僵化且脆弱。'组合优于继承'这一原则主张通过将小的、独立的功能模块组合在一起来构建复杂对象,而不是通过深层的类继承体系。这种方式能让系统更加灵活,更容易适应需求的变化。
"组合优于继承"(Composition Over Inheritance)是面向对象设计中的一个重要原则。它强调通过组合多个小的、专门的对象来构建复杂功能,而不是通过深层的继承层次。这种设计哲学让系统更加灵活、可维护,并且更容易适应变化。
继承的局限性
在深入了解组合模式之前,让我们先看看传统继承方式存在的问题:
1. 脆弱的基类问题
javascript
// 脆弱的基类示例
class Animal {
makeSound() {
console.log("动物发出了声音");
}
move() {
console.log("动物在移动");
// 某天,基类开发者添加了新功能
this.checkEnergyLevel();
}
// 新添加的方法
checkEnergyLevel() {
console.log("检查能量水平");
}
}
class Bird extends Animal {
makeSound() {
console.log("鸟儿啾啾叫");
}
// 重写移动方法
move() {
console.log("鸟儿在飞翔");
// 没有调用 checkEnergyLevel,可能导致基类功能失效
}
fly() {
console.log("鸟儿展翅高飞");
}
}
class Penguin extends Bird {
makeSound() {
console.log("企鹅嘎嘎叫");
}
// 企鹅不会飞,重写方法
move() {
console.log("企鹅在游泳");
}
fly() {
console.log("企鹅不会飞");
// 这个实现违反了里氏替换原则
throw new Error("企鹅不会飞!");
}
}
// 问题:基类的变化可能破坏所有子类
const bird = new Bird();
bird.move(); // "鸟儿在飞翔" - 没有检查能量水平
const penguin = new Penguin();
try {
penguin.fly(); // 抛出异常 - 破坏了多态性
} catch (error) {
console.log(error.message);
}2. 过度设计的问题
javascript
// 过度设计的继承层次
class Vehicle {
start() {
console.log("启动交通工具");
}
}
class MotorVehicle extends Vehicle {
start() {
super.start();
console.log("启动引擎");
}
}
class Car extends MotorVehicle {
start() {
super.start();
console.log("启动汽车系统");
}
}
class ElectricCar extends Car {
start() {
super.start();
console.log("启动电动系统");
}
}
class SelfDrivingCar extends ElectricCar {
start() {
super.start();
console.log("启动自动驾驶系统");
}
}
// 问题:每一个新功能都需要新的子类
const car = new SelfDrivingCar();
car.start();
// 输出多层嵌套的启动信息3. 违反开闭原则
javascript
class Shape {
draw() {
throw new Error("子类必须实现 draw 方法");
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
draw() {
console.log(`绘制半径为 ${this.radius} 的圆形`);
}
}
class Square extends Shape {
constructor(side) {
super();
this.side = side;
}
draw() {
console.log(`绘制边长为 ${this.side} 的正方形`);
}
}
// 现在需要添加颜色功能 - 必须修改基类或创建大量子类
class ColoredCircle extends Circle {
constructor(radius, color) {
super(radius);
this.color = color;
}
draw() {
console.log(`绘制${this.color}色的圆形`);
}
}
class ColoredSquare extends Square {
constructor(side, color) {
super(side);
this.color = color;
}
draw() {
console.log(`绘制${this.color}色的正方形`);
}
}
// 如果还需要透明度、边框等属性,组合爆炸!组合模式的解决方案
组合模式通过将功能分解为独立的、可重用的组件来解决继承的问题。
1. 基础组合示例
javascript
// 功能组件
class Engine {
constructor(type, power) {
this.type = type;
this.power = power;
}
start() {
console.log(`${this.type}引擎启动,功率 ${this.power} 马力`);
}
stop() {
console.log(`${this.type}引擎停止`);
}
}
class GPS {
constructor(version) {
this.version = version;
}
navigate(destination) {
console.log(`GPS ${this.version} 导航到 ${destination}`);
}
}
class AudioSystem {
constructor(brand) {
this.brand = brand;
this.isPlaying = false;
}
play() {
this.isPlaying = true;
console.log(`${this.brand} 音响开始播放音乐`);
}
stop() {
this.isPlaying = false;
console.log(`${this.brand} 音响停止播放`);
}
}
class Battery {
constructor(capacity) {
this.capacity = capacity; // kWh
this.charge = capacity; // 当前电量
}
charge(amount) {
this.charge = Math.min(this.capacity, this.charge + amount);
console.log(`充电 ${amount} kWh,当前电量 ${this.charge}/${this.capacity}`);
}
consume(amount) {
if (this.charge >= amount) {
this.charge -= amount;
console.log(
`消耗 ${amount} kWh,剩余电量 ${this.charge}/${this.capacity}`
);
return true;
}
console.log(`电量不足!需要 ${amount} kWh,只有 ${this.charge} kWh`);
return false;
}
}
// 通过组合创建汽车
class Car {
constructor(config = {}) {
this.engine = new Engine(
config.engineType || "汽油",
config.enginePower || 150
);
this.gps = config.hasGPS ? new GPS(config.gpsVersion || "2.0") : null;
this.audio = config.hasAudio
? new AudioSystem(config.audioBrand || "Sony")
: null;
this.battery = config.hasBattery
? new Battery(config.batteryCapacity || 50)
: null;
}
start() {
console.log("汽车启动流程开始");
if (this.battery && !this.battery.consume(1)) {
console.log("启动失败:电量不足");
return false;
}
this.engine.start();
if (this.gps) {
this.gps.navigate("预设目的地");
}
console.log("汽车启动完成");
return true;
}
stop() {
this.engine.stop();
this.audio?.stop();
console.log("汽车停止");
}
playMusic() {
if (this.audio) {
this.audio.play();
} else {
console.log("这辆车没有音响系统");
}
}
upgradeGPS(newVersion) {
if (this.gps) {
this.gps = new GPS(newVersion);
console.log(`GPS 升级到版本 ${newVersion}`);
} else {
this.gps = new GPS(newVersion);
console.log(`安装 GPS 版本 ${newVersion}`);
}
}
}
// 创建不同的汽车配置
const basicCar = new Car({
engineType: "汽油",
enginePower: 120,
});
const luxuryCar = new Car({
engineType: "V8汽油",
enginePower: 400,
hasGPS: true,
gpsVersion: "3.0",
hasAudio: true,
audioBrand: "Bose",
});
const electricCar = new Car({
engineType: "电动",
enginePower: 300,
hasGPS: true,
gpsVersion: "4.0",
hasAudio: true,
audioBrand: "B&O",
hasBattery: true,
batteryCapacity: 100,
});
// 使用示例
basicCar.start(); // 基础汽车
luxuryCar.start(); // 豪华汽车
luxuryCar.playMusic(); // 豪华汽车播放音乐
electricCar.start(); // 电动汽车2. 行为组合模式
javascript
// 行为组件
class Drawable {
constructor(shape, style = {}) {
this.shape = shape;
this.style = {
color: "black",
fillColor: "transparent",
lineWidth: 1,
...style,
};
}
draw(ctx, x, y) {
ctx.save();
ctx.strokeStyle = this.style.color;
ctx.fillStyle = this.style.fillColor;
ctx.lineWidth = this.style.lineWidth;
switch (this.shape) {
case "circle":
this.drawCircle(ctx, x, y);
break;
case "rectangle":
this.drawRectangle(ctx, x, y);
break;
case "triangle":
this.drawTriangle(ctx, x, y);
break;
}
ctx.restore();
}
drawCircle(ctx, x, y) {
ctx.beginPath();
ctx.arc(x, y, this.style.radius || 20, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
}
drawRectangle(ctx, x, y) {
const width = this.style.width || 40;
const height = this.style.height || 30;
ctx.fillRect(x - width / 2, y - height / 2, width, height);
ctx.strokeRect(x - width / 2, y - height / 2, width, height);
}
drawTriangle(ctx, x, y) {
const size = this.style.size || 25;
ctx.beginPath();
ctx.moveTo(x, y - size);
ctx.lineTo(x - size, y + size);
ctx.lineTo(x + size, y + size);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
}
class Movable {
constructor(speed = 5) {
this.speed = speed;
this.x = 0;
this.y = 0;
}
moveTo(x, y) {
this.x = x;
this.y = y;
}
moveBy(dx, dy) {
this.x += dx * this.speed;
this.y += dy * this.speed;
}
getPosition() {
return { x: this.x, y: this.y };
}
}
class Interactive {
constructor() {
this.onClick = null;
this.onHover = null;
this.isEnabled = true;
}
click() {
if (this.isEnabled && this.onClick) {
this.onClick();
}
}
hover() {
if (this.isEnabled && this.onHover) {
this.onHover();
}
}
enable() {
this.isEnabled = true;
}
disable() {
this.isEnabled = false;
}
}
class Animated {
constructor() {
this.animations = [];
this.isAnimating = false;
}
addAnimation(animation) {
this.animations.push(animation);
}
start() {
this.isAnimating = true;
this.animate();
}
stop() {
this.isAnimating = false;
}
animate() {
if (!this.isAnimating) return;
this.animations.forEach((animation) => {
if (animation.update()) {
animation.draw();
}
});
requestAnimationFrame(() => this.animate());
}
}
// 通过组合创建图形对象
class GameObject {
constructor(x, y, config = {}) {
this.drawable = config.drawable || null;
this.movable = config.movable || null;
this.interactive = config.interactive || null;
this.animated = config.animated || null;
if (this.movable) {
this.movable.moveTo(x, y);
}
}
update(deltaTime) {
// 更新所有组件
}
render(ctx) {
if (this.drawable && this.movable) {
const pos = this.movable.getPosition();
this.drawable.draw(ctx, pos.x, pos.y);
}
}
handleClick() {
this.interactive?.click();
}
handleHover() {
this.interactive?.hover();
}
}
// 使用示例
const canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 600;
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
// 创建一个可点击的圆形
const clickableCircle = new GameObject(100, 100, {
drawable: new Drawable("circle", {
radius: 30,
fillColor: "blue",
color: "darkblue",
}),
movable: new Movable(3),
interactive: new Interactive(),
});
clickableCircle.interactive.onClick = () => {
console.log("圆形被点击了!");
clickableCircle.drawable.style.fillColor =
clickableCircle.drawable.style.fillColor === "blue" ? "red" : "blue";
};
// 创建一个可移动的矩形
const movableRect = new GameObject(200, 200, {
drawable: new Drawable("rectangle", {
width: 60,
height: 40,
fillColor: "green",
}),
movable: new Movable(2),
});
// 动画循环
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
clickableCircle.update();
movableRect.update();
clickableCircle.render(ctx);
movableRect.render(ctx);
requestAnimationFrame(gameLoop);
}
gameLoop();
// 添加交互
canvas.addEventListener("click", (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const circlePos = clickableCircle.movable.getPosition();
const distance = Math.sqrt(
Math.pow(x - circlePos.x, 2) + Math.pow(y - circlePos.y, 2)
);
if (distance <= 30) {
clickableCircle.handleClick();
}
});
// 键盘控制移动
document.addEventListener("keydown", (e) => {
switch (e.key) {
case "ArrowUp":
movableRect.movable.moveBy(0, -1);
break;
case "ArrowDown":
movableRect.movable.moveBy(0, 1);
break;
case "ArrowLeft":
movableRect.movable.moveBy(-1, 0);
break;
case "ArrowRight":
movableRect.movable.moveBy(1, 0);
break;
}
});组合模式的实际应用
1. Web 组件系统
javascript
// 组件功能模块
class EventManager {
constructor() {
this.listeners = new Map();
}
on(event, handler) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(handler);
}
off(event, handler) {
if (this.listeners.has(event)) {
const handlers = this.listeners.get(event);
const index = handlers.indexOf(handler);
if (index > -1) {
handlers.splice(index, 1);
}
}
}
emit(event, ...args) {
if (this.listeners.has(event)) {
this.listeners.get(event).forEach((handler) => {
handler(...args);
});
}
}
}
class Validator {
constructor() {
this.rules = [];
this.errors = [];
}
addRule(field, validator, message) {
this.rules.push({ field, validator, message });
}
validate(data) {
this.errors = [];
let isValid = true;
for (const { field, validator, message } of this.rules) {
if (!validator(data[field])) {
this.errors.push({ field, message, value: data[field] });
isValid = false;
}
}
return isValid;
}
getErrors() {
return [...this.errors];
}
}
class Renderer {
constructor(template) {
this.template = template;
}
render(data) {
return this.template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return data[key] !== undefined ? data[key] : "";
});
}
}
class StateManager {
constructor(initialState = {}) {
this.state = { ...initialState };
this.subscribers = [];
}
setState(newState) {
const oldState = { ...this.state };
this.state = { ...this.state, ...newState };
this.notify(oldState, this.state);
}
getState() {
return { ...this.state };
}
subscribe(callback) {
this.subscribers.push(callback);
return () => {
const index = this.subscribers.indexOf(callback);
if (index > -1) {
this.subscribers.splice(index, 1);
}
};
}
notify(oldState, newState) {
this.subscribers.forEach((callback) => callback(newState, oldState));
}
}
// 组合创建表单组件
class FormComponent {
constructor(element, config = {}) {
this.element = element;
this.events = new EventManager();
this.validator = config.hasValidation ? new Validator() : null;
this.renderer = new Renderer(config.template || "<div>{{content}}</div>");
this.state = new StateManager(config.initialState || {});
this.setupValidation();
this.bindEvents();
}
setupValidation() {
if (!this.validator) return;
// 添加通用验证规则
this.validator.addRule(
"email",
(val) => typeof val === "string" && val.includes("@"),
"请输入有效的邮箱地址"
);
this.validator.addRule(
"required",
(val) => val !== null && val !== undefined && val !== "",
"此字段为必填项"
);
}
bindEvents() {
this.state.subscribe((newState, oldState) => {
this.render(newState);
this.events.emit("stateChange", newState, oldState);
});
this.element.addEventListener("submit", (e) => {
e.preventDefault();
this.handleSubmit();
});
}
handleSubmit() {
const formData = this.getFormData();
if (this.validator && !this.validator.validate(formData)) {
this.events.emit("validationError", this.validator.getErrors());
return;
}
this.events.emit("submit", formData);
}
getFormData() {
const formData = {};
const inputs = this.element.querySelectorAll("input, select, textarea");
inputs.forEach((input) => {
formData[input.name] = input.value;
});
return formData;
}
render(data) {
this.element.innerHTML = this.renderer.render(data);
}
validate() {
if (!this.validator) return true;
const formData = this.getFormData();
return this.validator.validate(formData);
}
setState(newState) {
this.state.setState(newState);
}
getState() {
return this.state.getState();
}
}
// 使用示例
const loginForm = new FormComponent(document.getElementById("loginForm"), {
hasValidation: true,
template: `
<form>
<div>
<label>邮箱:</label>
<input type="email" name="email" value="{{email}}">
</div>
<div>
<label>密码:</label>
<input type="password" name="password" value="{{password}}">
</div>
<button type="submit">登录</button>
<div class="errors">{{errors}}</div>
</form>
`,
initialState: {
email: "",
password: "",
errors: "",
},
});
// 添加自定义验证
loginForm.validator.addRule(
"password",
(val) => typeof val === "string" && val.length >= 6,
"密码至少需要6个字符"
);
// 监听事件
loginForm.events.on("submit", (formData) => {
console.log("表单提交:", formData);
// 发送登录请求
});
loginForm.events.on("validationError", (errors) => {
const errorMessages = errors
.map((err) => `${err.field}: ${err.message}`)
.join(", ");
loginForm.setState({ errors: errorMessages });
});2. 服务层组合
javascript
// 服务组件
class CacheService {
constructor() {
this.cache = new Map();
this.ttl = new Map();
}
set(key, value, expireTime = 5 * 60 * 1000) {
this.cache.set(key, value);
this.ttl.set(key, Date.now() + expireTime);
}
get(key) {
if (!this.cache.has(key)) return null;
if (Date.now() > this.ttl.get(key)) {
this.delete(key);
return null;
}
return this.cache.get(key);
}
delete(key) {
this.cache.delete(key);
this.ttl.delete(key);
}
clear() {
this.cache.clear();
this.ttl.clear();
}
}
class LoggerService {
constructor(level = "info") {
this.level = level;
}
log(message, level = "info") {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] [${level.toUpperCase()}] ${message}`);
}
error(message) {
this.log(message, "error");
}
warn(message) {
this.log(message, "warn");
}
info(message) {
this.log(message, "info");
}
}
class HttpService {
constructor(baseURL = "") {
this.baseURL = baseURL;
}
async get(url, options = {}) {
try {
const response = await fetch(`${this.baseURL}${url}`, {
method: "GET",
...options,
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
throw new Error(`请求失败: ${error.message}`);
}
}
async post(url, data, options = {}) {
try {
const response = await fetch(`${this.baseURL}${url}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
...options.headers,
},
body: JSON.stringify(data),
...options,
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
throw new Error(`请求失败: ${error.message}`);
}
}
}
class AuthService {
constructor() {
this.http = new HttpService("https://api.example.com");
this.cache = new CacheService();
this.logger = new LoggerService("auth");
}
async login(email, password) {
this.logger.info(`用户登录尝试: ${email}`);
try {
const response = await this.http.post("/auth/login", {
email,
password,
});
// 缓存用户信息
this.cache.set("user", response.user, 30 * 60 * 1000); // 30分钟
this.cache.set("token", response.token, 30 * 60 * 1000);
this.logger.info(`用户登录成功: ${email}`);
return response;
} catch (error) {
this.logger.error(`登录失败: ${error.message}`);
throw error;
}
}
async logout() {
try {
const token = this.cache.get("token");
if (token) {
await this.http.post("/auth/logout", { token });
}
this.cache.delete("user");
this.cache.delete("token");
this.logger.info("用户登出成功");
} catch (error) {
this.logger.error(`登出失败: ${error.message}`);
}
}
getCurrentUser() {
return this.cache.get("user");
}
isAuthenticated() {
return this.cache.get("token") !== null;
}
}
class UserService {
constructor() {
this.http = new HttpService("https://api.example.com");
this.cache = new CacheService();
this.logger = new LoggerService("user");
this.authService = new AuthService();
}
async getUserProfile(userId) {
const cacheKey = `profile:${userId}`;
// 检查缓存
let profile = this.cache.get(cacheKey);
if (profile) {
this.logger.info(`从缓存获取用户资料: ${userId}`);
return profile;
}
try {
profile = await this.http.get(`/users/${userId}`);
// 缓存结果
this.cache.set(cacheKey, profile, 10 * 60 * 1000); // 10分钟
this.logger.info(`获取用户资料成功: ${userId}`);
return profile;
} catch (error) {
this.logger.error(`获取用户资料失败: ${error.message}`);
throw error;
}
}
async updateProfile(userId, updates) {
this.logger.info(`更新用户资料: ${userId}`);
try {
const updatedProfile = await this.http.put(`/users/${userId}`, updates);
// 更新缓存
const cacheKey = `profile:${userId}`;
this.cache.set(cacheKey, updatedProfile, 10 * 60 * 1000);
this.logger.info(`用户资料更新成功: ${userId}`);
return updatedProfile;
} catch (error) {
this.logger.error(`更新用户资料失败: ${error.message}`);
throw error;
}
}
}
// 使用示例
const authService = new AuthService();
const userService = new UserService();
// 用户登录
authService
.login("[email protected]", "password123")
.then(() => {
console.log("登录成功");
// 获取用户资料
const user = authService.getCurrentUser();
return userService.getUserProfile(user.id);
})
.then((profile) => {
console.log("用户资料:", profile);
})
.catch((error) => {
console.error("操作失败:", error);
});组合模式的优势
1. 灵活性
javascript
// 动态组合功能
class TaskManager {
constructor() {
this.features = {
logging: null,
priority: null,
deadline: null,
notification: null,
persistence: null,
};
}
addFeature(name, feature) {
if (this.features.hasOwnProperty(name)) {
this.features[name] = feature;
console.log(`功能 ${name} 已添加`);
}
}
removeFeature(name) {
if (this.features[name]) {
this.features[name] = null;
console.log(`功能 ${name} 已移除`);
}
}
executeTask(task) {
console.log(`执行任务: ${task.name}`);
// 按顺序执行功能
this.features.logging?.log(task);
this.features.priority?.process(task);
this.features.deadline?.check(task);
const result = this.performTask(task);
this.features.notification?.send(result);
this.features.persistence?.save(result);
return result;
}
performTask(task) {
console.log(`任务 ${task.name} 执行完成`);
return { task, success: true, timestamp: Date.now() };
}
}
// 功能组件
class LoggingFeature {
log(task) {
console.log(`[LOG] 开始执行任务: ${task.name}`);
}
}
class PriorityFeature {
process(task) {
if (task.priority === "high") {
console.log(`[PRIORITY] 高优先级任务,立即执行`);
}
}
}
class DeadlineFeature {
check(task) {
if (task.deadline && Date.now() > task.deadline) {
console.log(`[DEADLINE] 警告:任务已过期`);
}
}
}
class NotificationFeature {
send(result) {
console.log(`[NOTIFY] 任务完成通知: ${result.task.name}`);
}
}
class PersistenceFeature {
save(result) {
console.log(`[PERSIST] 保存任务结果到数据库`);
}
}
// 动态配置任务管理器
const taskManager = new TaskManager();
// 根据需求添加功能
taskManager.addFeature("logging", new LoggingFeature());
taskManager.addFeature("priority", new PriorityFeature());
taskManager.addFeature("deadline", new DeadlineFeature());
// 运行时添加或移除功能
taskManager.addFeature("notification", new NotificationFeature());
const task1 = {
name: "发送邮件",
priority: "high",
deadline: Date.now() + 3600000, // 1小时后过期
};
taskManager.executeTask(task1);
// 移除通知功能
taskManager.removeFeature("notification");
const task2 = {
name: "生成报告",
priority: "normal",
};
taskManager.executeTask(task2);2. 测试友好性
javascript
// 可测试的组合设计
class EmailService {
constructor(emailProvider, logger, validator) {
this.emailProvider = emailProvider;
this.logger = logger;
this.validator = validator;
}
async sendEmail(to, subject, body) {
this.logger.info(`准备发送邮件到: ${to}`);
if (!this.validator.isValidEmail(to)) {
throw new Error("无效的邮箱地址");
}
try {
const result = await this.emailProvider.send(to, subject, body);
this.logger.info(`邮件发送成功: ${result.messageId}`);
return result;
} catch (error) {
this.logger.error(`邮件发送失败: ${error.message}`);
throw error;
}
}
}
// 测试用的模拟组件
class MockEmailProvider {
async send(to, subject, body) {
console.log(`[MOCK] 发送邮件: ${to} - ${subject}`);
return { messageId: "mock-id-123", status: "sent" };
}
}
class MockLogger {
info(message) {
console.log(`[MOCK INFO] ${message}`);
}
error(message) {
console.log(`[MOCK ERROR] ${message}`);
}
}
class MockValidator {
isValidEmail(email) {
return email.includes("@");
}
}
// 测试
async function testEmailService() {
const mockProvider = new MockEmailProvider();
const mockLogger = new MockLogger();
const mockValidator = new MockValidator();
const emailService = new EmailService(
mockProvider,
mockLogger,
mockValidator
);
try {
await emailService.sendEmail(
"[email protected]",
"测试邮件",
"这是一封测试邮件"
);
console.log("测试通过");
} catch (error) {
console.error("测试失败:", error.message);
}
}
testEmailService();组合模式的最佳实践
1. 接口设计
javascript
// 定义清晰的接口
class IRenderable {
render(context) {
throw new Error("子类必须实现 render 方法");
}
}
class IUpdatable {
update(deltaTime) {
throw new Error("子类必须实现 update 方法");
}
}
class IDestroyable {
destroy() {
throw new Error("子类必须实现 destroy 方法");
}
}
// 实现接口的组件
class SpriteRenderer extends IRenderable {
constructor(image, x, y) {
super();
this.image = image;
this.x = x;
this.y = y;
}
render(context) {
context.drawImage(this.image, this.x, this.y);
}
}
class PhysicsComponent extends IUpdatable {
constructor(gravity = 9.8) {
super();
this.velocity = { x: 0, y: 0 };
this.gravity = gravity;
}
update(deltaTime) {
this.velocity.y += this.gravity * deltaTime;
return this.velocity;
}
}
class LifecycleManager extends IDestroyable {
constructor() {
super();
this.resources = [];
}
addResource(resource) {
this.resources.push(resource);
}
destroy() {
this.resources.forEach((resource) => {
if (resource.destroy) {
resource.destroy();
}
});
this.resources = [];
}
}2. 依赖注入
javascript
// 依赖注入容器
class DIContainer {
constructor() {
this.services = new Map();
this.singletons = new Map();
}
register(name, factory, options = {}) {
this.services.set(name, { factory, options });
}
resolve(name) {
const service = this.services.get(name);
if (!service) {
throw new Error(`服务 ${name} 未注册`);
}
if (service.options.singleton) {
if (!this.singletons.has(name)) {
this.singletons.set(name, service.factory(this));
}
return this.singletons.get(name);
}
return service.factory(this);
}
}
// 使用依赖注入
const container = new DIContainer();
container.register("logger", () => new LoggerService(), { singleton: true });
container.register("cache", () => new CacheService(), { singleton: true });
container.register("http", () => new HttpService(), { singleton: true });
container.register("authService", (container) => {
return new AuthService(
container.resolve("http"),
container.resolve("cache"),
container.resolve("logger")
);
});
// 使用服务
const authService = container.resolve("authService");总结
"组合优于继承"是现代软件设计的核心原则之一。通过组合模式,你可以:
- 构建灵活的系统:通过组合不同的功能模块,创建多样化的对象
- 提高代码复用性:独立的功能组件可以在多个地方重用
- 增强可维护性:修改一个组件不会影响其他组件
- 改善测试性:可以独立测试每个组件
- 支持运行时变化:可以动态添加、移除或替换功能
组合模式的核心思想是将复杂系统分解为小的、专门的、可组合的组件。这种设计哲学不仅适用于面向对象编程,也适用于函数式编程和其他编程范式。
记住,好的设计不是关于继承层次有多深,而是关于组件之间如何优雅地协作。通过组合,你可以构建出更加灵活、可维护和可扩展的软件系统。