← 返回首页
设计模式基础教程(三十三)
发表时间:2021-09-03 22:05:03
访问者模式

1.访问者模式

对于系统中的某些对象,它们存储在同一个集合中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有所不同,访问者模式为解决这类问题而诞生。

访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。

访问者模式包含如下角色: - Vistor: 抽象访问者 - ConcreteVisitor: 具体访问者 - Element: 抽象元素 - ConcreteElement: 具体元素 - ObjectStructure: 对象结构

2.实例

顾客在超市中将选择的商品,如苹果、图书等放在购物车中,然后到收银员处付款。在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量,之后收银员计算价格时也需要访问购物车内顾客所选择的商品。此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品,而顾客和收银员作为访问这些商品的访问者,他们需要对商品进行检查和计价。不同类型的商品其访问形式也可能不同,如苹果需要过秤之后再计价,而图书不需要。使用访问者模式来设计该购物过程。

项目结构图如下:

设计产品接口

public interface Product {
    void accept(Visitor visitor);
}

设计抽象访问者类

public abstract class Visitor {
    protected String name;
    public void setName(String name) {
        this.name = name;
    }
    public abstract void visit(Apple apple);
    public abstract void visit(Book book);
}

设计苹果和图书产品

//Apple.java
public class Apple implements Product {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

//Book.java
public class Book implements Product {
    @Override
    public void accept(Visitor visitor) {
            visitor.visit(this);
    }
}

设计收银员类

public class Saler extends Visitor {

    @Override
    public void visit(Apple apple) {
        System.out.println("收银员"+this.name+"给苹果过秤,然后计算其价格!");
    }
    @Override
    public void visit(Book book) {
        System.out.println("收银员"+this.name+"直接计算书的价格!");
    }
}

设计客户类


public class Customer extends Visitor {

    @Override
    public void visit(Apple apple) {
        System.out.println("顾客"+this.name+"选苹果!");
    }

    @Override
    public void visit(Book book) {
        System.out.println("顾客"+this.name+"买书!");
    }

}

设计购物车类

public class BuyBasket {

    private List<Product> list=new ArrayList<>();

    public void accept(Visitor visitor){
        Iterator<Product> iterator=list.iterator();
        while(iterator.hasNext()){
            Product product=iterator.next();
            product.accept(visitor);
        }
    }

    public void addProduct(Product product){
        list.add(product);
    }

    public void removeProduct(Product product){
        list.remove(product);
    }
}

XML解析工具类

public class XmlUtils {

    // 该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
    public static Object getBean() {
        try {
            // 创建文档对象
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc= builder.parse(XmlUtils.class .getClassLoader().getResourceAsStream("config.xml"));

            // 获取包含类名的文本节点
            NodeList nl = doc.getElementsByTagName("className");
            String className = nl.item(0).getTextContent();

            // 通过类名生成实例对象并将其返回
            Class c = Class.forName(className);
            Object obj = c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

配置文档

<?xml version="1.0"?>
<config>
    <className>com.simoniu.domain.Saler</className>
</config>

测试类

public class Client {

    public static void main(String[] args) {
        Product book1=new Book();
        Product book2=new Book();
        Product apple1=new Apple();

        BuyBasket basket=new BuyBasket();
        basket.addProduct(book1);
        basket.addProduct(book2);
        basket.addProduct(apple1);

        Visitor visitor=(Visitor) XmlUtils.getBean();
        visitor.setName("小丽");
        basket.accept(visitor);
    }
}

运行结果:
收银员小丽直接计算书的价格!
收银员小丽直接计算书的价格!
收银员小丽给苹果过秤,然后计算其价格!