趣解设计模式之《小王与他的Apple商店》

〇、小故事

小王开了一个Apple商店,每天销售量都很不错,但是,近期却有一件事让他很苦恼,那就是针对不同的角色用户,商品的售价是各不同的

比如说,对于普通消费者 来说,对于最新的Apple产品,都是原价销售的;

那么,对于学生消费群体 来说,由于每年开学都会有高校折扣的政策,为了减少学生客户群体的购买压力,是在原价的基础上打8折销售的;

那么,对于企业大客户 来说,很多互联网公司都会采购Apple电脑作为办公电脑,往往这种企业采购的方式购买电脑的数量会非常的大。所以,为了促进与企业的合作,是在原价的基础上打5折销售的;

随着后续购买用户角色类型的增多,就会造成一大堆的if-else判断逻辑,来返回不同角色对应的不同价格 ,这样无疑会使得代码维护性越来越差,那有什么更好的办法解决这个问题吗?当然有了,解决办法就是我们今天要介绍的设计模式------访问者模式

一、模式定义

访问者模式Visitor Pattern

表示一个作用于某个对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

根据上面的小故事,我们可以看到小王的主要困扰就是针对不同的用户类型要有不同的折扣,这样随着用户类型的增多或者减少,我们都要频繁的修改电脑组件类(CPUMemory)里的if-else价格判断逻辑。那我们来思考一下,哪些是变化的?哪些是不变的呢?

变化 】用户类型,如:普通用户学生用户企业采购用户......

不变 】计算机组件类标准价格(此处我们不考虑促销活动的折扣或免减),如:CPUMemory......

既然变化的是用户类型,那么我们何不把计算机组件中判断金额的逻辑部分转移到用户类型中呢?这样计算机组件就永久稳定了。

有了这样的想法之后,计算机组件每个类都只需要包含标价就可以了 。然后,针对不同的用户类型打不同的折扣,这部分逻辑,就可以抽离到计算机组件类中

二、模式类图

根据上面的描述,我们首先来创建计算机组件接口ComputerComponent.java,以及两个计算机组件的实现类CPU.javaMemory.java。然后再创建计算机类Computer.java,用于将计算机的各个组件类组合起来。那么针对不用的用户类型,我们首先创建访问者接口Visitor.java,然后创建3个实现类,分别是普通用户访问者PersonVisitor.java学生用户访问者StudentVisitor.java企业采购访问者CompanyVisitor.java。具体类图请见如下所示:

三、代码实现

创建计算机组件类ComputerComponent.java

java 复制代码
public interface ComputerComponent {
    int price(); // 售价
    String version(); // 硬件版本
    String desc(); // 描述
    void accept(Visitor visitor);
}

创建CPU类Cpu.java

java 复制代码
public class Cpu implements ComputerComponent {
    public int price = 100; // 全国标准售价
    @Override
    public int price() {
        return 100;
    }
    @Override
    public String version() {
        return "v1";
    }
    @Override
    public String desc() {
        return "英特尔CPU";
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visitorCpu(this);
    }
}

创建内存类Memory.java

java 复制代码
public class Memory implements ComputerComponent {
    public int price = 400; // 全国标准售价
    @Override
    public int price() {
        return price;
    }
    @Override
    public String version() {
        return "v4";
    }
    @Override
    public String desc() {
        return "金士顿内存";
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visitorMemory(this);
    }
}

创建访问者类Visitor.java

java 复制代码
public interface Visitor {
    void visitorCpu(Cpu cpu);
    void visitorMemory(Memory memory);
    int price();
    String visiterName();
}

创建个人用户类(不打折)PersonVisitor.java

java 复制代码
public class PersonVisitor implements Visitor {
    public int totalPrice; // 总售价
    @Override
    public void visitorCpu(Cpu cpu) {
        totalPrice += cpu.price();
    }
    @Override
    public void visitorMemory(Memory memory) {
        totalPrice += memory.price();
    }
    @Override
    public int price() {
        return totalPrice;
    }
    @Override
    public String visiterName() {
        return "个人用户";
    }
}

创建学生用户(校园计划,打8折)StudentVisitor.java

java 复制代码
public class StudentVisitor implements Visitor {
    public int totalPrice; // 总售价
    @Override
    public void visitorCpu(Cpu cpu) {
        totalPrice += cpu.price() * 0.8;
    }
    @Override
    public void visitorMemory(Memory memory) {
        totalPrice += memory.price() * 0.9;
    }
    @Override
    public int price() {
        return totalPrice;
    }
    @Override
    public String visiterName() {
        return "学生用户";
    }
}

创建公司大客户(打5折)CompanyVisitor.java

java 复制代码
public class CompanyVisitor implements Visitor {
    public int totalPrice; // 总售价
    @Override
    public void visitorCpu(Cpu cpu) {
        totalPrice += cpu.price() * 0.5;
    }
    @Override
    public void visitorMemory(Memory memory) {
        totalPrice += memory.price() * 0.4;
    }
    @Override
    public int price() {
        return totalPrice;
    }
    @Override
    public String visiterName() {
        return "公司大客户";
    }
}

创建计算机类,组合上面的组件Computer.java

java 复制代码
public class Computer {
    private ComputerComponent memory;
    private ComputerComponent cpu;
    public Computer() {
        memory = new Memory();
        cpu = new Cpu();
    }
    
    /**
     * 攒机方法
     * @Visitor 买电脑的客户角色
     */
    public void buildComputer(Visitor visitor) {
        // 买cpu
        cpu.accept(visitor);
        // 买内存
        memory.accept(visitor);
    }
}

创建测试类VisitorTest.java

java 复制代码
public class VisitorTest {
    public static void main(String[] args) {
        Computer computer = new Computer();
        Visitor personVisitor = new PersonVisitor();
        Visitor studentVisitor = new StudentVisitor();
        Visitor companyVisitor = new CompanyVisitor();
        
        computer.buildComputer(personVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", personVisitor.visiterName(), personVisitor.price()));
        
        computer.buildComputer(studentVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", studentVisitor.visiterName(), studentVisitor.price()));
        
        computer.buildComputer(companyVisitor);
        System.out.println(String.format("针对%s,每台电脑售价为:%s元", companyVisitor.visiterName(), companyVisitor.price()));
    }
}

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享

更多技术干货,欢迎大家关注公众号"爪哇缪斯" ~ \(^o^)/ ~ 「干货分享,每天更新」

相关推荐
凌虚(失业了求个工作)1 小时前
AI 声音:数字音频、语音识别、TTS 简介与使用示例
人工智能·后端·python·深度学习·语音识别
Achou.Wang1 小时前
go结构体匿名“继承“方法冲突时继承优先顺序
开发语言·后端·golang
DARLING Zero two♡1 小时前
当前就业形势下C++方向后端开发学习指南
开发语言·c++·后端·团队开发
豆 腐2 小时前
Spring Boot【三】
java·spring boot·后端
你邻座的怪同学2 小时前
SpringBoot集成ESAPI
java·spring boot·后端
哎呦没2 小时前
宠物领养平台构建:SpringBoot技术路线图
spring boot·后端·宠物
Tdm_8885 小时前
C# 反射详解
java·开发语言·后端·c#·asp.net
桃园码工8 小时前
第二章:编写第一个 Go 程序 1.Hello World 程序 --Go 语言轻松入门
开发语言·后端·golang
小贾Coder8 小时前
【速通GO】基础结构和语法
开发语言·后端·golang
夜色呦9 小时前
SpringBoot框架助力欢迪迈手机商城快速开发
spring boot·后端·性能优化