树形结构

1 解决的问题

  1. 树形结构数据处理上,若将父节点与子节点分开抽象成类,比较麻烦。

2 组合模式

简单说,就是寻求树形结构中所有节点的特点,然后整合到抽象类中。

3 模式结构

4 实现代码

代码一:

public interface Shape {
    void move(int x, int y);
    void paint(Graphics graphics);
}
 
abstract class BaseShape implements Shape {
    @Override    public void move(int x, int y) {   }
    @Override    public void paint(Graphics graphics) {    }
}
 
// 叶节点
public class Dot extends BaseShape {
    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.fillRect(x - 1, y - 1, getWidth(), getHeight());
    }
}
public class Circle extends BaseShape {
    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        graphics.drawOval(x, y, getWidth() - 1, getHeight() - 1);
    }
}
 
// 组合
public class CompoundShape extends BaseShape {
    protected List<Shape> children = new ArrayList<>();
	public CompoundShape(Shape... components) {
        super(0, 0, Color.BLACK);
        add(components);
    }
    @Override
    public void move(int x, int y) {
        for (Shape child : children) {
            child.move(x, y);
        }
    }
    @Override
    public void paint(Graphics graphics) {
        if (isSelected()) {
            enableSelectionStyle(graphics);
            graphics.drawRect(getX() - 1, getY() - 1, getWidth() + 1, getHeight() + 1);
            disableSelectionStyle(graphics);
        }
        for (refactoring_guru.composite.example.shapes.Shape child : children) {
            child.paint(graphics);
        }
    }
}
 
// 测试
new CompoundShape(
		new Circle(10, 10, 10, Color.BLUE),
		new CompoundShape(
			new Circle(110, 110, 50, Color.RED),
			new Dot(160, 160, Color.RED)
		),
		new CompoundShape(
				new Rectangle(250, 250, 100, 100, Color.GREEN),
				new Dot(240, 240, Color.GREEN),
				new Dot(240, 360, Color.GREEN),
				new Dot(360, 360, Color.GREEN),
				new Dot(360, 240, Color.GREEN)
		)
);

代码二:

public abstract class Component {
    private String position;
    private String job;
    public Component(String position, String job) {
        this.position = position;
        this.job = job;
    }
    abstract void removeComponent(Component component);
    abstract void check();
}
 
public class Manager extends Component {
    private List<Component> components = new ArrayList<>();
    public Manager(String position, String job) {
        super(position, job);
    }
    @Override    public void addComponent(Component component) {        components.add(component);    }
    @Override    void removeComponent(Component component) {        components.remove(component);    }
    @Override    public void check() {
        for (Component component : components)
            component.check();
    }
}
 
public class Employee extends Component {
    public Employee(String position, String job) {
        super(position, job);
    }
    @Override    void addComponent(Component component) {        System.out.println("职员没有管理权限");    }
    @Override    void removeComponent(Component component) {        System.out.println("职员没有管理权限");    }
    @Override    void check() {    }
}

5 透明组合模式和安全组合模式

透明组合模式:

  • 将所有节点涉及的所有方法都放到抽象类中,各自节点针对自己需要实现特定功能,场景规则下用不到的方法使用抽象类中默认空实现。
  • 违背了接口隔离原则。客户端不应依赖它不需要的接口。如果一个接口在实现时,部分方法由于冗余被客户端空实现,则应该将接口拆分,让实现类只需依赖自己需要的接口方法。
  • 对于外界来说叶节点和枝节点是透明的,它们具备完全一致的接口。
  • 大多数选择。

安全组合模式:

  • 抽象类中只包含所有节点共有的方法,实现类中根据情况增加需要的方法。
  • 安全方式遵循了接口隔离原则。
  • 对于外界来说不够透明,实现类不具备相同的接口。对于客户端来说,无法将 Manager 和 Employee 统一声明为 Component 类,必须区别对待。

6 应用场景

  • 树状结构对象
  • 客户端以相同方式来处理简单和复杂对象。

7 经典应用例子

设计模式 | 组合模式及典型应用 - 掘金

  • java.awt
  • Java 集合
  • Mybatis SqlNode