😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》本专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~
什么是组合模式
组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示“整体-部分”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性,可以用统一的方式处理它们
组合模式由以下几个角色组成:
组件(Component)
:定义了组合对象和叶子对象的共有方法和属性,并且可以为子对象提供默认的实现。它可以是抽象类或接口。
叶子(Leaf)
:表示组合中的叶子对象,没有子对象。
组合(Composite)
:表示组合中的组合对象,可以包含子对象。它实现了组件的方法,并在需要的情况下调用子对象的方法。
客户端(Client)
:通过组合模式的接口来操作组合对象和叶子对象。
组合模式适用场景
- 当需要表示对象的部分-整体层次结构,并希望以统一的方式处理整体和部分时,可以使用组合模式。例如,文件系统中的目录和文件的层次结构。
- 当希望客户端忽略组合对象和叶子对象的区别,统一地对待它们时,可以使用组合模式。客户端不需要知道当前操作的是组合对象还是叶子对象,只需要调用统一的接口即可。
- 当希望对组合对象和叶子对象进行增加、删除、遍历等操作时,可以使用组合模式。组合模式使得对整个树形结构的操作更加简单和灵活。
需要注意的是,组合模式并不是为了解决对象的层次关系而存在的,而是通过将对象组合成树形结构来统一处理整体和部分的关系。在应用组合模式时,需要合理划分组合对象和叶子对象,并确保它们之间的接口和行为一致性,以达到更好的扩展性和灵活性。
生活场景
在餐厅中,菜单通常是由多个菜品组成的。我们可以将菜单系统抽象为一个树形结构,其中树的节点表示菜单或菜品分类,而叶子节点表示具体的菜品。
餐厅的菜单系统中可能包含以下节点和叶子节点:
菜单节点(Menu)
:表示一个完整的菜单,可能包含多个菜品或菜单分类
菜单分类节点(Menu Category)
:表示菜单中的分类,如主菜、甜点、饮品等。这个节点可以包含多个叶子节点和子菜单节点
菜品节点(Dish)
:表示具体的菜品,包含菜品的名称、描述和价格等信息
通过组合模式,我们可以使用统一的接口来操作菜单系统。无论是获取整个菜单,还是获取某个分类下的菜品,我们都可以使用相同的方式来处理整体和部分。
例如,我们可以调用菜单节点的方法来获取整个菜单的内容,并在其中递归调用子菜单节点的方法来获取菜单分类下的具体菜品。同样地,我们也可以调用菜单分类节点的方法来获取该分类下的菜品列表。
组合模式的好处在于,我们可以方便地对菜单系统进行扩展和修改,无需改变客户端的代码。例如,如果菜单中新增了一个新的菜品分类,我们只需要添加一个新的菜单分类节点即可,而不会影响到其他部分。
总而言之,组合模式可以让我们以统一的方式处理菜单系统中的整体和部分,提供了更好的扩展性和灵活性。
代码案例
首先,我们定义一个抽象的组件接口 MenuComponent,表示菜单系统中的组件(菜单、菜单分类和菜品):
public interface MenuComponent {
void display();
}
然后,我们创建具体的菜单节点类 Menu,表示一个完整的菜单:
import java.util.ArrayList;
import java.util.List;
public class Menu implements MenuComponent {
private String name;
private List<MenuComponent> components;
public Menu(String name) {
this.name = name;
this.components = new ArrayList<>();
}
public void addComponent(MenuComponent component) {
components.add(component);
}
public void removeComponent(MenuComponent component) {
components.remove(component);
}
@Override
public void display() {
System.out.println("菜单:" + name);
System.out.println("--------------------");
for (MenuComponent component : components) {
component.display();
System.out.println();
}
}
}
接下来,我们创建菜单分类节点类 MenuCategory,表示菜单中的分类:
import java.util.ArrayList;
import java.util.List;
public class MenuCategory implements MenuComponent {
private String name;
private List<MenuComponent> components;
public MenuCategory(String name) {
this.name = name;
this.components = new ArrayList<>();
}
public void addComponent(MenuComponent component) {
components.add(component);
}
public void removeComponent(MenuComponent component) {
components.remove(component);
}
@Override
public void display() {
System.out.println("菜单分类:" + name);
System.out.println("*******************");
for (MenuComponent component : components) {
component.display();
}
}
}
最后,我们创建菜品节点类 Dish,表示具体的菜品:
public class Dish implements MenuComponent {
private String name;
private String description;
private double price;
public Dish(String name, String description, double price) {
this.name = name;
this.description = description;
this.price = price;
}
@Override
public void display() {
System.out.println("菜品:" + name);
System.out.println("描述:" + description);
System.out.println("价格:" + price + "元");
}
}
现在,我们可以在客户端代码中使用组合模式来操作菜单系统:
public class CombinationPatternTest {
public static void main(String[] args) {
// 创建菜单
Menu menu = new Menu("餐厅菜单");
// 创建菜单分类
MenuCategory mainCourse = new MenuCategory("主菜");
MenuCategory dessert = new MenuCategory("甜点");
// 创建具体菜品
Dish steak = new Dish("牛排", "美味的牛排", 50.0);
Dish pasta = new Dish("意大利面", "经典的意式面食", 30.0);
Dish cake = new Dish("蛋糕", "甜甜的蛋糕", 20.0);
// 将菜品添加到相应的菜单分类中
mainCourse.addComponent(steak);
mainCourse.addComponent(pasta);
dessert.addComponent(cake);
// 将菜单分类添加到菜单中
menu.addComponent(mainCourse);
menu.addComponent(dessert);
// 显示整个菜单
menu.display();
}
}
通过以上代码,我们创建了一个餐厅的菜单系统,并使用组合模式来组织菜单、菜单分类和菜品之间的关系。客户端代码可以通过调用菜单的 display() 方法来展示整个菜单的内容。
组合模式的优缺点
组合模式的优点:
- 简化客户端代码:组合模式通过统一的接口,使得客户端可以一致地处理单个对象和组合对象,无需区分它们的具体类型,从而简化了客户端代码的复杂性。
- 增加新组件方便:由于组合模式使用了递归结构,因此添加新的组件非常方便。无论是添加一个新的叶子节点还是一个新的组合节点,都可以通过修改少量代码来完成。
- 灵活性和扩展性:组合模式使得系统具备了较高的灵活性和可扩展性。可以根据需要构建复杂的组合结构,随时增加、删除或替换组件,而无需修改现有代码。
组合模式的缺点:
- 设计复杂性增加:由于组合模式涉及到递归和层次结构的组织,因此设计和实现时会增加一定的复杂性,特别是在处理具有多层嵌套的组合结构时。
- 不适合所有情况:组合模式更适合表示树形结构的场景,如果对象之间的关系不是层次化的,或者对象的行为不一致,使用组合模式可能不太合适。
- 运行效率低:在使用组合模式时,由于需要通过递归遍历整个组合结构,可能会导致性能下降。特别是当组合结构很大时,遍历的时间会显著增加。
综上所述,组合模式通过统一接口、灵活的组合结构和简化客户端代码的特点,为处理树形结构的对象提供了一种有效的方式。然而,使用组合模式需要权衡设计复杂性和运行效率,确保在合适的场景下使用。
结语
本章节主要介绍了组合模式、组合模式适用场景、组合模式的优缺点,并以餐厅菜单的生活场景模拟组合模式的样例代码,如果本文对你有用,欢迎关注收藏评论,后续将陆续推出贴切生活的搞笑讲解方式带大家一起学编程~