Appearance
组合设计模式 / Composite
组合设计模式允许我们将对象组合成树形结构来标识“部分-整体”的层次结构。这种模式使得代码可以一致地处理单个对象和对象组合。
基于 Class 的代码示例
javascript
class Employee {
constructor(id, name) {
// id 属性用于在删除时进行查找
this.id = id;
this.name = name;
}
print() {
console.log(`Employee: ${this.name}`);
}
}
class Manager extends Employee {
constructor(id, name) {
super(id, name);
this.employees = [];
}
add(employee) {
this.employees.push(employee);
}
remove(id) {
const index = this.employees.findIndex((item) => item.id === id);
if (index >= 0) {
this.employees.splice(index, 1);
}
}
print() {
console.log(`Manager: ${this.name}`);
this.employees.forEach((employee) => employee.print());
}
}
const ming = new Employee(1, 'Ming');
const anny = new Employee(2, 'Anny');
const bob = new Manager(3, 'Bob');
bob.add(ming);
bob.add(anny);
bob.print();
在上述代码中,Manager
对象实例可以添加和删除 Employee
实例,并且拥有自己的 print()
方法,该方法还会调用所有 Employee
实例的 print()
方法。
React 函数式组件代码示例
javascript
import React from 'react';
// 共享接口 (这里我们不需要共享接口,因为React的组件本身就是函数)
// class Component {
// render() {
// return null;
// }
// }
// 叶子节点
const Post = ({ title, content, comments }) => (
<div className="post">
<h2>{title}</h2>
<p>{content}</p>
{comments.map((comment, index) => (
<Comment key={index} author={comment.author} text={comment.text} />
))}
</div>
);
// 叶子节点
const Comment = ({ author, text }) => (
<div className="comment">
<span>{author}:</span>
<p>{text}</p>
</div>
);
// 组合节点
const BlogPost = ({ post, comments }) => <Post title={post.title} content={post.content} comments={comments} />;
// 使用
const post = {
title: 'My First Post',
content: 'Welcome to my blog!',
};
const comments = [
{ author: 'Alice', text: 'Great post!' },
{ author: 'Bob', text: 'Thanks for sharing.' },
];
ReactDOM.render(<BlogPost post={post} comments={comments} />, document.getElementById('root'));
这样做的好处:
灵活性:由于客户端代码与组合结构的交互方式是统一的,因此,你可以轻松地添加新的组件类型或改变现有组件的行为,而不会影响到客户端代码。例如,如果你需要添加一个新的评论类型,如“匿名评论”,只需要创建一个新的组件类并遵循相同的接口,而无需修改已有的
Comment
或Post
类。可扩展性:通过组合,你可以轻松地增加或减少组件的层次,添加更多的功能。例如,如果博客应用需要添加“点赞”功能,你可以创建一个
LikeButton
组件,并将其添加到Post
或Comment
中,而无需更改整体结构。代码复用:组合模式允许你重用单个组件,因为它们可以独立于组合存在。例如,
Comment
组件不仅可以用于博客,还可以用于论坛、社交媒体等其他场景。清晰的结构:组合模式提供了一种清晰的方式来表示对象之间的部分-整体关系,使得代码更易于理解和维护。当需求变化时,你可以更容易地追踪和修改这些关系。
例如,假设你的博客应用现在要求用户可以对评论进行回复。你可以创建一个新的 Reply
组件,它同样遵循 Component
接口,然后在 Comment
组件中添加一个 replies
属性,并修改 Comment
的 render
方法以显示回复。由于所有组件都遵循相同的接口,你不需要修改 Post
或 BlogPost
的代码,只需关注 Comment
和新的 Reply
组件即可。这就是组合设计模式在需求变更时的优势。