设计模式学习第十五节 访问者模式

本文介绍了访问者模式,用于在不改变数据结构的前提下定义作用于元素的新操作。通过一个组装电脑的例子展示了如何使用访问者模式来处理不同人群的折扣计算,如学生和公司采购员。代码实现中,访问者接口定义了针对电脑各部件的折扣方法,具体访问者类实现了这些方法。访问者模式的优点在于扩展性好,但缺点是可能导致元素变更困难且违反依赖倒转原则。适合于数据结构稳定而功能常变的系统。
摘要由CSDN通过智能技术生成

概述

    基本介绍
    1、访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各个元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
    2、主要将数据结构于数据操作分离,解决数据结构和操作耦合的问题。
    3、访问者模式的基本工作原理是:在被访问类的里面添加一个对外提供接待访问者的接口。
    4、访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有什么关联),同时需要避免这些操作污染这些对象的类,可以选用访问者模式。
    5、对象结构比较稳定,但经常需要在此对象结构上定义新的操作,使用访问者模式更容易扩展。对象结构不稳定,使用访问者模式会使得程序更加复杂。
    6、一句话总结:在结构不变的情况下,动态的改变对于内部元素的访问。
    类图
在这里插入图片描述

    类图说明:
    1、Visitor 是抽象访问者,为该对象结构中的ConcreteElement每一个类声明一个Visit操作。
    2、ConcreteVisitor:是具体访问者,实现每个Visitor声明的操作,是每个操作具体实现。
    3、ObejctStruture:能枚举它的元素,可以提供一个高层的接口,用来允许访问者访问它的元素:
    4、Element:定义一个accept()方法,接收一个访问者对象。
    5、ConcreteElement:具体元素,实现了accept方法。

代码实现

    小需求:组装一台电脑,每个部件针对不同的人群有不同的折扣,比如说,电脑由主机、屏幕、键盘、鼠标构成,结构不再变动。学生人群主机8折、屏幕7折、键盘8折、鼠标8折;公司采购员人群主机6折、屏幕6折、键盘5折、鼠标5折等等。可以使用访问者模式实现,不然就需要在Computer类中添加各种判断,每增加一种人群类型都需要新增一个判断。
    根据需求与访问这模式画出类图
在这里插入图片描述
    代码实现

package com.example.pattern.visitor;

import lombok.Getter;
import lombok.Setter;

/**
 * 访问者模式
 */

interface Visitor {

    void visitMainframe(Mainframe mainframe);

    void visitScreen(Screen screen);

    void visitKeyboard(Keyboard keyboard);

    void visitMouse(Mouse mouse);

}

@Setter
@Getter
class StudentTypeVisitor implements Visitor {

    private Double totalPrice = 0d;

    @Override
    public void visitMainframe(Mainframe mainframe) {
        this.totalPrice += mainframe.getPrice() * 0.8;
    }

    @Override
    public void visitScreen(Screen screen) {
        this.totalPrice += screen.getPrice() * 0.9;
    }

    @Override
    public void visitKeyboard(Keyboard keyboard) {
        this.totalPrice += keyboard.getPrice() * 0.7;
    }

    @Override
    public void visitMouse(Mouse mouse) {
        this.totalPrice += mouse.getPrice() * 0.6;
    }
}

@Setter
@Getter
class CorpTypeVisitor implements Visitor {

    private Double totalPrice = 0d;

    @Override
    public void visitMainframe(Mainframe mainframe) {
        this.totalPrice += mainframe.getPrice() * 0.7;
    }

    @Override
    public void visitScreen(Screen screen) {
        this.totalPrice += screen.getPrice() * 0.6;
    }

    @Override
    public void visitKeyboard(Keyboard keyboard) {
        this.totalPrice += keyboard.getPrice() * 0.5;
    }

    @Override
    public void visitMouse(Mouse mouse) {
        this.totalPrice += mouse.getPrice() * 0.5;
    }
}


@Getter
@Setter
public class Computer { // Computer结构已经被固定 就是这四个模块

    private ComputerPart mainframe = new Mainframe(); //主机
    private ComputerPart screen = new Screen(); // 屏幕
    private ComputerPart keyboard = new Keyboard(); // 键盘
    private ComputerPart mouse = new Mouse(); // 鼠标

    public void accept(Visitor visitor) {
        this.mainframe.accept(visitor);
        this.screen.accept(visitor);
        this.keyboard.accept(visitor);
        this.mouse.accept(visitor);
    }

}

abstract class ComputerPart { // 抽象类 电脑的一部分

    abstract void accept(Visitor visitor);

    abstract Double getPrice();
}

class Mainframe extends ComputerPart { // 主机

    @Override
    public void accept(Visitor visitor) {
        visitor.visitMainframe(this);
    }

    @Override
    public Double getPrice() {
        return 5000d;
    }
}

class Screen extends ComputerPart { // 屏幕

    @Override
    public void accept(Visitor visitor) {
        visitor.visitScreen(this);
    }

    @Override
    public Double getPrice() {
        return 900d;
    }
}

class Keyboard extends ComputerPart { // 键盘

    @Override
    public void accept(Visitor visitor) {
        visitor.visitKeyboard(this);
    }

    @Override
    public Double getPrice() {
        return 60d;
    }
}

class Mouse extends ComputerPart { // 鼠标

    @Override
    public void accept(Visitor visitor) {
        visitor.visitMouse(this);
    }

    @Override
    public Double getPrice() {
        return 50d;
    }
}

class Client {
    public static void main(String[] args) {
        Computer computer = new Computer();
        StudentTypeVisitor studentTypeVisitor = new StudentTypeVisitor();
        computer.accept(studentTypeVisitor);
        System.out.println(studentTypeVisitor.getTotalPrice());

        CorpTypeVisitor corpTypeVisitor = new CorpTypeVisitor();
        computer.accept(corpTypeVisitor);
        System.out.println(corpTypeVisitor.getTotalPrice());
        // 经过代码实现在添加其它类型的人群是比较简单的,只需要实现 Visitor接口实现方法即可
        // 但是如何Computer类结构有变化 比如有耳机模块,整个模式将不再好维护,变得比较复杂。

    }
}

使用细节

    优点
    1、访问这模式符合单一职责原则,让程序具有更好的扩展性。
    2、访问者模式可以对功能进行统一,可以做报表等数据结构非常稳定的系统。
    缺点
    1、具体元素对访问者公布细节,也就是说访问者关注了其它类的内部细节,不符合迪米特法则,这样也就造成了具体元素的变更比较困难,修改起来比较麻烦。
    2、违背了依赖倒转原则,访问者依赖的是具体元素,而不是抽象元素。
    3、因此访问者模式适合于拥有稳定的数据结构、但是功能经常变化的系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值