〇、小故事
小王开了一个Apple商店,每天销售量都很不错,但是,近期却有一件事让他很苦恼,那就是针对不同的角色用户,商品的售价是各不同的。
比如说,对于普通消费者来说,对于最新的Apple产品,都是原价
销售的;
那么,对于学生消费群体来说,由于每年开学都会有高校折扣的政策,为了减少学生客户群体的购买压力,是在原价的基础上打8折
销售的;
那么,对于企业大客户来说,很多互联网公司都会采购Apple电脑作为办公电脑,往往这种企业采购的方式购买电脑的数量会非常的大。所以,为了促进与企业的合作,是在原价的基础上打5折
销售的;
随着后续购买用户角色类型的增多,就会造成一大堆的if-else判断逻辑,来返回不同角色对应的不同价格,这样无疑会使得代码维护性越来越差,那有什么更好的办法解决这个问题吗?当然有了,解决办法就是我们今天要介绍的设计模式——访问者模式。
一、模式定义
访问者模式(Visitor Pattern
)
表示一个作用于某个对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
根据上面的小故事,我们可以看到小王的主要困扰就是针对不同的用户类型要有不同的折扣,这样随着用户类型的增多或者减少,我们都要频繁的修改电脑组件类(CPU
、Memory
)里的if-else
价格判断逻辑。那我们来思考一下,哪些是变化的?哪些是不变的呢?
【变化】用户类型,如:
普通用户
、学生用户
、企业采购用户
……【不变】计算机组件类标准价格(此处我们不考虑促销活动的折扣或免减),如:
CPU
、Memory
……
既然变化的是用户类型,那么我们何不把计算机组件中判断金额的逻辑部分转移到用户类型中呢?这样计算机组件就永久稳定了。
有了这样的想法之后,计算机组件每个类都只需要包含标价就可以了。然后,针对不同的用户类型打不同的折扣,这部分逻辑,就可以抽离到计算机组件类中。
二、模式类图
根据上面的描述,我们首先来创建计算机组件接口: ComputerComponent.java
,以及两个计算机组件的实现类:CPU.java
和Memory.java
。然后再创建计算机类:Computer.java
,用于将计算机的各个组件类组合起来。那么针对不用的用户类型,我们首先创建访问者接口:Visitor.java
,然后创建3个实现类,分别是普通用户访问者:PersonVisitor.java
、学生用户访问者:StudentVisitor.java
和企业采购访问者:CompanyVisitor.java
。具体类图请见如下所示:
三、代码实现
创建计算机组件类:ComputerComponent.java
public interface ComputerComponent { int price(); // 售价 String version(); // 硬件版本 String desc(); // 描述 void accept(Visitor visitor); }
创建CPU类:Cpu.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
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
public interface Visitor { void visitorCpu(Cpu cpu); void visitorMemory(Memory memory); int price(); String visiterName(); }
创建个人用户类(不打折):PersonVisitor.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
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
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
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
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^)/ ~ 「干货分享,每天更新」