设计模式
设计模式分为创建型模式、结构型模式和行为型模式。
创建型模式:创建对象。
结构型模式:把复杂结构分解为多个类,分解的是类本身(包括算法和属性)。
行为型模式:把复杂算法分解到多个类,分解的是算法。
行为模式-访问者模式
访问者模式是为了在不改变原有类结构的情况下增加一种算法,这种算法将在类外实现,并且将类对象传递给算法。
UML 图
关键在 Element 接口,声明了一个方法来接收访问者。访问者将具体的 Element 传递给算法。
示例代码
public interface Element {
void accept(Visitor visitor);
}
public class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public interface Visitor {
void visit(ConcreteElementA elementA);
void visit(ConcreteElementB elementB);
}
public class ConcreteVisitor implements Visitor {
@Override
public void visit(ConcreteElementA elementA) {
System.out.println("ConcreteVisitor visit ConcreteElementA");
}
@Override
public void visit(ConcreteElementB elementB) {
System.out.println("ConcreteVisitor visit ConcreteElementB");
}
}
public class Client {
public static void main(String[] args) {
Element elementA = new ConcreteElementA();
Element elementB = new ConcreteElementB();
Visitor visitor = new ConcreteVisitor();
elementA.accept(visitor);
elementB.accept(visitor);
}
}
输出:
ConcreteVisitor visit ConcreteElementA
ConcreteVisitor visit ConcreteElementB
为什么不能重载替代访问者模式
使用重载会遇到一个问题:子类的类型会被擦除。
示例代码:
interface Graphic{
void draw();
}
class Shape implements Graphic{
@Override
public void draw() {
System.out.println("Shape");
}
}
class Dot extends Shape{
@Override
public void draw() {
System.out.println("Dot");
}
}
class Circle extends Dot{
@Override
public void draw() {
System.out.println("Circle");
}
}
class Exporter{
public void export(Shape shape){
System.out.println("export shape");
}
public void export(Dot dot){
System.out.println("export dot");
}
public void export(Circle circle){
System.out.println("export circle");
}
}
public class Client {
public static void main(String[] args) {
Shape shape = new Circle();
Exporter exporter = new Exporter();
exporter.export(shape);
}
}
上面的代码运行后输出:
export shape
Shape 有多个子类,每个子类都重写了 draw 方法,但是在运行时,调用的是 Shape 的 draw 方法,而不是 Circle 的 draw 方法。这是因为 Java 中的重载是静态绑定的(编译时),而不是动态绑定的(编译后的运行时)。
而访问者模式的实现 visitor.visit(this) 中 this 的类型在编译时就确定了。