title: 使用组合模式进行Spring Boot开发
date: 2023-08-11 22:23:47
cover: https://coupon-image.oss-cn-shanghai.aliyuncs.com/image/blog/java.jpeg
categories:

  • springBoot
    tags:
  • springBoot3
  • 组合模式
  • composite mode
  • ai

使用组合模式进行Spring Boot开发

前言

组合模式是一种结构型设计模式,用于将对象组合成树形结构以表示"整体-部分"的层次结构。组合模式允许客户端统一对待单个对象和组合对象,使得客户端无需关心对象的具体类型,而只需要调用统一的接口。

在Spring Boot开发中,组合模式可以用于处理整体和部分之间的关系,使得我们可以对对象组合进行统一的操作。

组合模式的优点:

  1. 高内聚、低耦合。组合模式使得客户端并不关心自己处理的是组合对象还是叶子对象,简化了客户端代码。
  2. 容易扩展。可以通过添加新的叶子对象或组合对象来扩展功能。
  3. 方便递归操作。组合对象中的组合对象可以递归包含更多层次的组合对象和叶子对象,对整个树形结构进行递归遍历。

实现

开发例子

构建树形结构

在Spring Boot中,我们可能需要构建树形结构的数据,如部门组织结构、菜单导航等。每个节点(部门或菜单项)都有自己特定的属性和行为,同时也可以包含其他节点。

我们可以使用组合模式来定义一个抽象的节点接口Node,然后实现具体的节点类Department和MenuItem,以及一个组合节点类CompositeNode来表示包含其他节点的节点。

public interface Node {
    void display();
}

public class Department implements Node {
    private String name;
    
    // 省略了构造函数和其他属性
    
    @Override
    public void display() {
        System.out.println("Department: " + name);
    }
}

public class MenuItem implements Node {
    private String name;
    
    // 省略了构造函数和其他属性
    
    @Override
    public void display() {
        System.out.println("Menu item: " + name);
    }
}

public class CompositeNode implements Node {
    private List<Node> nodes = new ArrayList<>();
    
    public void add(Node node) {
        nodes.add(node);
    }
    
    public void remove(Node node) {
        nodes.remove(node);
    }
    
    @Override
    public void display() {
        for (Node node : nodes) {
            node.display();
        }
    }
}

通过组合模式,我们可以使用统一的接口Node来处理单个节点和组合节点,并对整个树形结构进行统一的操作。

Department dept1 = new Department("IT Department");
Department dept2 = new Department("HR Department");
MenuItem menu1 = new MenuItem("Menu Item 1");
MenuItem menu2 = new MenuItem("Menu Item 2");

CompositeNode root = new CompositeNode();
CompositeNode subNode1 = new CompositeNode();
CompositeNode subNode2 = new CompositeNode();

root.add(dept1);
root.add(dept2);
root.add(subNode1);
root.add(subNode2);
subNode1.add(menu1);
subNode2.add(menu2);

root.display();

处理订单和订单项

在Spring Boot开发中,我们可能需要处理订单和订单项的关系。每个订单可以包含多个订单项,而每个订单项又可以有自己的属性和行为。

我们可以使用组合模式来定义一个抽象的订单组件接口OrderComponent,然后实现具体的订单类Order和订单项类OrderItem,以及一个组合订单项类CompositeOrderItem来表示包含多个订单项的订单。

public interface OrderComponent {
    void display();
}

public class Order implements OrderComponent {
    private String orderId;
    private List<OrderComponent> items = new ArrayList<>();
    
    // 省略了构造函数和其他属性
    
    public void addItem(OrderComponent item) {
        items.add(item);
    }
    
    public void removeItem(OrderComponent item) {
        items.remove(item);
    }
    
    @Override
    public void display() {
        System.out.println("Order ID: " + orderId);
        for (OrderComponent item : items) {
            item.display();
        }
    }
}

public class OrderItem implements OrderComponent {
    private String productId;
    private int quantity;
    
    // 省略了构造函数和其他属性
    
    @Override
    public void display() {
        System.out.println("Product ID: " + productId + ", Quantity: " + quantity);
    }
}

public class CompositeOrderItem implements OrderComponent {
    private List<OrderComponent> items = new ArrayList<>();
    
    public void addItem(OrderComponent item) {
        items.add(item);
    }
    
    public void removeItem(OrderComponent item) {
        items.remove(item);
    }
    
    @Override
    public void display() {
        for (OrderComponent item : items) {
            item.display();
        }
    }
}

通过组合模式,我们可以使用统一的接口OrderComponent来处理单个订单项和组合订单项,并对整个订单进行统一的操作。

OrderItem item1 = new OrderItem("P1", 2);
OrderItem item2 = new OrderItem("P2", 3);
OrderItem item3 = new OrderItem("P3", 1);
CompositeOrderItem compositeItem = new CompositeOrderItem();
compositeItem.addItem(item2);
compositeItem.addItem(item3);

Order order = new Order("O1");
order.addItem(item1);
order.addItem(compositeItem);

order.display();

使用组合模式实现菜单栏

在Spring Boot应用中,我们经常需要实现菜单栏功能,其中菜单栏可能包含多个菜单项和子菜单。我们可以使用组合模式来实现菜单栏,将菜单项和子菜单都视为组合对象。

public interface MenuComponent {
    void display();
}

public class MenuItem implements MenuComponent {
    private String name;

    public MenuItem(String name) {
        this.name = name;
    }
  
    @Override
    public void display() {
        System.out.println(name);
    }
}

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);
    }

    @Override
    public void display() {
        System.out.println(name);
        for (MenuComponent component : components) {
            component.display();
        }
    }
}


在使用时,我们可以创建菜单栏,并添加菜单项和子菜单。

MenuComponent menuBar = new Menu("Menu Bar");

MenuComponent fileMenu = new Menu("File");
fileMenu.addComponent(new MenuItem("New"));
fileMenu.addComponent(new MenuItem("Open"));
fileMenu.addComponent(new MenuItem("Save"));

MenuComponent editMenu = new Menu("Edit");
editMenu.addComponent(new MenuItem("Cut"));
editMenu.addComponent(new MenuItem("Copy"));
editMenu.addComponent(new MenuItem("Paste"));

menuBar.addComponent(fileMenu);
menuBar.addComponent(editMenu);

menuBar.display();

通过以上示例,我们可以看到使用组合模式可以方便地实现菜单栏功能,使得客户端可以统一地处理菜单项和子菜单。

使用组合模式实现目录结构

在某些场景下,我们可能需要处理目录结构,其中目录可以包含子目录和文件。我们可以使用组合模式来实现目录结构,将目录和文件都视为组合对象。

public interface FileSystemComponent {
    void display();
}

public class File implements FileSystemComponent {
    private String name;

    public File(String name) {
        this.name = name;
    }

    @Override
    public void display() {
        System.out.println(name);
    }
}

public class Directory implements FileSystemComponent {
    private String name;
    private List<FileSystemComponent> components;

    public Directory(String name) {
        this.name = name;
        this.components = new ArrayList<>();
    }

    public void addComponent(FileSystemComponent component) {
        components.add(component);
    }

    @Override
    public void display() {
        System.out.println(name);
        for (FileSystemComponent component : components) {
            component.display();
        }
    }
}

在使用时,我们可以创建目录结构,并添加子目录和文件。

FileSystemComponent root = new Directory("Root");

FileSystemComponent dir1 = new Directory("Dir1");
dir1.addComponent(new File("File1.txt"));
dir1.addComponent(new File("File2.txt"));

FileSystemComponent dir2 = new Directory("Dir2");
dir2.addComponent(new File("File3.txt"));

root.addComponent(dir1);
root.addComponent(dir2);

root.display();

通过以上示例,我们可以看到使用组合模式可以方便地实现目录结构,使得客户端可以统一地处理子目录和文件。

组合图形

定义组合图形的接口:

public interface Shape {

  void draw(); // 绘制

  void add(Shape shape); // 添加子图形

  void remove(Shape shape); // 移除子图形

}

实现基本图形类:

// 点
public class Dot implements Shape {

  @Override
  public void draw() {
    System.out.println("Draw dot");
  }

  // 省略了add()和remove(),因为点没有子图形
}

// 线
public class Line implements Shape {

  @Override
  public void draw() {
    System.out.println("Draw line");
  }

  // 省略了add()和remove(),因为线没有子图形  
}

// 矩形
public class Rectangle implements Shape {

  @Override 
  public void draw() {
    System.out.println("Draw rectangle");
  }

  // 省略了add()和remove(),因为矩形没有子图形
}

然后实现组合图形类:

public class CompositeShape implements Shape {
  
  // 用list存储组成这个组合图形的所有子图形
  private List<Shape> shapes = new ArrayList<>();

  public void add(Shape shape) {
    shapes.add(shape);
  }

  public void remove(Shape shape) {
    shapes.remove(shape); 
  }

  @Override
  public void draw() {
    // 递归绘制自己以及所有子图形
    for (Shape shape : shapes) {
      shape.draw();
    }
  }

}

客户端代码示例:

CompositeShape shape1 = new CompositeShape();
shape1.add(new Dot());
shape1.add(new Line());

CompositeShape shape2 = new CompositeShape();
shape2.add(new Rectangle());
shape2.add(new Dot());
shape2.add(shape1); // 嵌套

shape2.draw(); // 递归绘制

通过组合模式可以方便地组合各种基本图形,形成复杂的组合图形,并统一进行操作。

总结

组合模式通过定义统一的组合对象接口,客户端可以一致地使用组合对象和叶子对象,从而简化客户端代码,提高程序的灵活性。组合对象可以递归包含其他组合对象和叶子对象,形成复杂的树形层次结构。

本篇文章由AI生成