定义

将对象组合成树形结构以表示“部分——整体”的层次结构

菜单有子菜单,子菜单还有子菜单,可以一直递归下去

使设计变得抽象

image.png

使用场景

  • 处理树形结构
  • 忽略组合与单个对象的差异

Demo设计

假设要展示课程目录,子目录可能还会有子目录,适合使用组合模式

默认方法抛异常,以免出现一些不符合业务场景的现象出现

组件接口

定义一个接口目录组件接口,不管是实体类还是目录类都继承此接口都可以添加到树形结构中

  1. public interface CatalogComponent {
  2. default void add(CatalogComponent catalogComponent) {
  3. throw new UnsupportedOperationException("不支持添加操作");
  4. }
  5. default void remove(CatalogComponent catalogComponent) {
  6. throw new UnsupportedOperationException("不支持删除操作");
  7. }
  8. default String getName() {
  9. throw new UnsupportedOperationException("不支持获取名称操作");
  10. }
  11. default Double getPrice() {
  12. throw new UnsupportedOperationException("不支持获取价格操作");
  13. }
  14. default void print() {
  15. throw new UnsupportedOperationException("不支持打印操作");
  16. }
  17. }

抛异常的话转换成json会出错,还是改成空方法吧

  1. public interface CatalogComponent {
  2. default void add(CatalogComponent catalogComponent) {
  3. }
  4. default void remove(CatalogComponent catalogComponent) {
  5. }
  6. default String getName() {
  7. return null;
  8. }
  9. default Double getPrice() {
  10. return null;
  11. }
  12. default void print() {
  13. }
  14. }

实体类

课程类

  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. public class Course implements CatalogComponent {
  5. private String courseName;
  6. private Double coursePrice;
  7. @Override
  8. public String getName() {
  9. return this.courseName;
  10. }
  11. @Override
  12. public Double getPrice() {
  13. return this.coursePrice;
  14. }
  15. @Override
  16. public void print() {
  17. System.out.println(this);
  18. }
  19. }

目录类

这里使用Data注解是为了好转化成json,也好打印list的结构

  1. @Data
  2. public class CourseCatalog implements CatalogComponent {
  3. private List<CatalogComponent> items = new ArrayList<>();
  4. private String name;
  5. public CourseCatalog(String name) {
  6. this.name = name;
  7. }
  8. @Override
  9. public String getName() {
  10. return this.name;
  11. }
  12. @Override
  13. public void add(CatalogComponent catalogComponent) {
  14. items.add(catalogComponent);
  15. }
  16. @Override
  17. public void remove(CatalogComponent catalogComponent) {
  18. items.remove(catalogComponent);
  19. }
  20. @Override
  21. public void print() {
  22. System.out.println(this);
  23. }
  24. }

测试方法

  1. public static void main(String[] args) {
  2. //操作系统课程目录
  3. CatalogComponent systemCatalog = new CourseCatalog("操作系统");
  4. //操作系统课程
  5. CatalogComponent linuxCourse = new Course("Linux", 11);
  6. CatalogComponent windowsCourse = new Course("Windows", 11);
  7. systemCatalog.add(linuxCourse);
  8. systemCatalog.add(windowsCourse);
  9. //java课程目录
  10. CatalogComponent javaCourseCatalog = new CourseCatalog("java课程目录");
  11. //java课程
  12. CatalogComponent javaSeCourse = new Course("JavaSE", 11);
  13. //项目课程目录
  14. CatalogComponent mallCatalog = new CourseCatalog("项目");
  15. CatalogComponent mallCourse1 = new Course("电商项目1期", 77);
  16. CatalogComponent mallCourse2 = new Course("电商项目2期", 77);
  17. mallCatalog.add(mallCourse1);
  18. mallCatalog.add(mallCourse2);
  19. javaCourseCatalog.add(javaSeCourse);
  20. javaCourseCatalog.add(mallCatalog);
  21. CatalogComponent mainCatalog = new CourseCatalog("主目录");
  22. mainCatalog.add(systemCatalog);
  23. mainCatalog.add(javaCourseCatalog);
  24. mainCatalog.print();
  25. }

将打印出来的对象格式化一下就是这样,实现树形结构,子菜单的子菜单
可以将此对象转换为json传给前端用于显示

  1. CourseCatalog(
  2. items=[
  3. CourseCatalog(items=
  4. [
  5. Course(courseName=Linux, coursePrice=11.0),
  6. Course(courseName=Windows, coursePrice=11.0)
  7. ], name=操作系统),
  8. CourseCatalog(items=
  9. [
  10. Course(courseName=JavaSE, coursePrice=11.0),
  11. CourseCatalog(items=
  12. [
  13. Course(courseName=电商项目1期, coursePrice=77.0),
  14. Course(courseName=电商项目2期, coursePrice=77.0)
  15. ], name=项目)
  16. ], name=java课程目录)],name=主目录
  17. )

小结

组合模式,将多个类实现同一接口或继承同一父类