设计模式之visitor模式,人人能懂的有趣实例

时间:2023-03-09 01:41:21
设计模式之visitor模式,人人能懂的有趣实例

设计模式,现在在网上随便搜都一大堆,为什么我还要写“设计模式”的章节呢?

两个原因:

1.本人觉得这是一个有趣的设计模式使用实例,所以记下来;

2.看着设计模式很牛逼,却不知道怎么在实战中应用出来。希望这个实例能给学习者一个参考,一点启发。

注意:本文是个人对设计模式的见解,不会出现大家常见的设计模式的概念。此文只作为一个实例。建议初学者参杂着别人博文一起读。

在此,向《大话设计模式》作者吴强前辈致敬

一、 Visitor(访问者)模式

关键词:访问者, 被访问者(元素),元素群,双重注入,操作

访问者模式的作用:对【元素】、【访问者】和【对元素的操作】进行单独抽象和封装,一旦这些【访问者】的增加或者是【对元素的操作】发生变化,不需要修改【元素】。

二、故事背景

程序员小明到了新的软件园,呆了半个月之后,发现附近没有快餐店,人流特别多。于是决定投资开一家快餐店,参考"某乐园"的运营模式。快餐店很快就装修好了。小明参考各路快餐店,很快就设计出了几款菜式。经过深思熟虑,小明对点餐计费环节,用了Visitor模式。

三、设计分析

每道菜(为了直观,这里没用商品,而是把汤和饭也作为菜品之一)作为最小的单元(元素);

每个点餐的客户作为访问者;

每一份快餐的菜单,则归类为对菜的操作。

四、参考事例

1.菜的抽象父类

public abstract class Element {
protected String name; //菜名
protected float price; //价格
protected int weight; //份量
abstract public void 供给(Visitor visitor);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
} }

2.食客接口

public interface Visitor {
abstract public void 选菜( Element element );
}

3.各种菜品继承菜的父类

/**
* 卷心菜
* @author 南城草
*
*/
public class Cabbage extends Element { public Cabbage(int weight) {
this();
this.weight = weight;
this.price = price*weight;
}
public Cabbage() {
this.name = "卷心菜";
this.price = 2;
this.weight = 1;
} @Override
public void 供给(Visitor visitor) {
visitor.选菜(this);
} }
/**
* 饭
* @author 南城草
*
*/
public class Meal extends Element { public Meal(int weight) {
this();
     this.weight = weight;
this.price = price*weight;
}
public Meal() {
this.name = "饭";
this.price = 2;
this.weight = 1;
} @Override
public void 供给(Visitor visitor) {
visitor.选菜(this);
} }
/**
* 烧鸭
* @author 南城草
*
*/
public class RoastDuck extends Element { public RoastDuck(int weight) {
this();
this.weight = weight;
this.price = price*weight;
}
public RoastDuck() {
this.name = "烧鸭";
this.price = 8;
this.weight = 1;
} @Override
public void 供给(Visitor visitor) {
visitor.选菜(this);
} }
/**
* 叉烧
* @author 南城草
*
*/
public class RoastPork extends Element { public RoastPork(int weight) {
this();
this.weight = weight;
this.price = price*weight;
}
public RoastPork() {
this.name = "叉烧";
this.price = 8;
this.weight = 1;
} @Override
public void 供给(Visitor visitor) {
visitor.选菜(this);
} }
/**
* 汤
* @author 南城草
*
*/
public class Soup extends Element { public Soup(int weight) {
this();
this.weight = weight;
this.price = price*weight;
}
public Soup() {
this.name = "汤";
this.price = 3;
this.weight = 1;
} @Override
public void 供给(Visitor visitor) {
visitor.选菜(this);
} }

……后面省略了快餐店多种菜式

4.普通客户 实现访客者(Visitor)接口

/**
* 普通客户
* @author 南城草
*
*/
public class NormalVisitor implements Visitor { @Override
public void 选菜(Element element) {
Element food = ((Element) element);
System.out.println(food.getName() +food.getWeight()+ "份!");
} }

……后面省略多种不同客户的优惠实现(什么会员用户打折,会员积分都在这里拓展)

5.下单类

/**
* 普通菜单
* @author 南城草
*
*/
public class Lunchbox {
private HashMap<String, Element> elements;
private float allPrice = 0; public Lunchbox() {
elements = new HashMap();
} public void Attach(Element element) {
elements.put(element.getName(), element);
} public void Detach(Element element) {
elements.remove(element);
} public Element getElemente(String name) {
return elements.get(name);
} public void Accept(Visitor visitor) {
for (Element e : elements.values()) {
e.供给(visitor);
allPrice += e.getPrice() * e.getWeight();
}
System.out.print("总价:"+allPrice);
}
}

……这里省略了多种点餐单,什么节日满减,都可以在这里拓展

5.测试类——一个普通用户过来,要点菜啦

public class MainTest {
public static void main(String[] args) {
Lunchbox lunchbox = new Lunchbox(); lunchbox.Attach(new RoastDuck(1));
lunchbox.Attach(new Meal(2));
lunchbox.Attach(new Soup(1)); lunchbox.Accept(new NormalVisitor());
} }

6.测试结果

饭1份!
烧鸭1份!
汤1份!
总价:15.0

三、总结

访客模式的优缺点:这里不做总结,百度很多。

事例中的优缺点:

优点:菜品的新增,直接增加类就可以了;

访客的变化,直接增加类实现接口就可以了;

制定新的销售手段,直接增加下单类就可以了;

这符合“开闭原则”。

缺点:很明显,不能对菜品进行修改。

四、与本章节无关

本人技术有限,如果错误或者不合理的地方,欢迎联系我整改。

突然写此章节,是一个偶然的机会,想到了这个有趣的设计模式例子,就写了下来。后续如果生活中发现符合其它设计模式的有趣例子,会持续增加。