注:示例来自《大话设计模式》
假如现有如下一段代码
package Test28;
public class Program {
public static void main(String[] args) {
System.out.println("男人成功时,背后多半有一个伟大的女人。");
System.out.println("女人成功时,背后大多有一个不成功的男人。");
System.out.println("男人失败时,闷头喝酒,谁也不用劝。");
System.out.println("女人失败时,眼泪汪汪,谁也劝不了。");
System.out.println("男人恋爱时,凡事不懂也要装懂。");
System.out.println("女人恋爱时,遇事懂也装作不懂。");
}
}
下面我们使用面向对象的方式进行重构 代码实现如下
人类
package Test28;
//人
public abstract class Person {
protected String action;
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
//得到结论或反应
public abstract void GetConclusion();
}
男人类
package Test28;
//男人
public class Man extends Person {
//得到结论或反应
@Override
public void GetConclusion() {
if (action == "成功")
{
System.out.println(this.getClass().getSimpleName()+action+"时,背后多半有一个伟大的女人。");
}
else if (action == "失败")
{
System.out.println(this.getClass().getSimpleName()+action+"时,闷头喝酒,谁也不用劝。");
}
else if (action == "恋爱")
{
System.out.println(this.getClass().getSimpleName()+action+"时,凡事不懂也要装懂。");
}
}
}
女人类
package Test28;
//女人
public class Woman extends Person {
//得到结论或反应
@Override
public void GetConclusion() {
if (action == "成功")
{
System.out.println(this.getClass().getSimpleName()+action+"时,背后大多有一个不成功的男人。");
}
else if (action == "失败")
{
System.out.println(this.getClass().getSimpleName()+action+"时,眼泪汪汪,谁也劝不了。");
}
else if (action == "恋爱")
{
System.out.println(this.getClass().getSimpleName()+action+"时,遇事懂也装作不懂。");
}
}
}
客户端代码
package Test28;
import java.util.ArrayList;
import java.util.List;
public class Program {
public static void main(String[] args) {
List persons = new ArrayList();
Person man1 = new Man();
man1.setAction("成功");
persons.add(man1);
Person woman1 = new Woman();
woman1.setAction("成功");
persons.add(woman1);
Person man2 = new Man();
man2.setAction("失败");
persons.add(man2);
Person woman2 = new Woman();
woman2.setAction("失败");
persons.add(woman2);
Person man3 = new Man();
man3.setAction("恋爱");
persons.add(man3);
Person woman3 = new Woman();
woman3.setAction("恋爱");
persons.add(woman3);
for (Person item : persons)
{
item.GetConclusion();
}
}
}
上面的写法 男人类与女人类中if else太多了 而且如果现在要增加一个结婚的状态 这两个类都需要增加分支判断 下面我们使用访问者模式进行重构 代码如下
状态的抽象类和人的抽象类
package Test28;
//状态
public abstract class Action {
//得到男人结论或反应
public abstract void GetManConclusion(Man concreteElementA);
//得到女人结论或反应
public abstract void GetWomanConclusion(Woman concreteElementB);
}
package Test28;
//人
public abstract class Person {
//接受
public abstract void Accept(Action visitor);
}
具体状态类
package Test28;
//成功
public class Success extends Action {
@Override
public void GetManConclusion(Man concreteElementA) {
System.out.println(concreteElementA.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,背后多半有一个伟大的女人。");
}
@Override
public void GetWomanConclusion(Woman concreteElementB) {
System.out.println(concreteElementB.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,背后大多有一个不成功的男人。");
}
}
package Test28;
//失败
public class Failing extends Action {
@Override
public void GetManConclusion(Man concreteElementA) {
System.out.println(concreteElementA.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,闷头喝酒,谁也不用劝。");
}
@Override
public void GetWomanConclusion(Woman concreteElementB) {
System.out.println(concreteElementB.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,眼泪汪汪,谁也劝不了。");
}
}
package Test28;
//恋爱
public class Amativeness extends Action {
@Override
public void GetManConclusion(Man concreteElementA) {
System.out.println(concreteElementA.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,凡事不懂也要装懂。");
}
@Override
public void GetWomanConclusion(Woman concreteElementB) {
System.out.println(concreteElementB.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,遇事懂也装作不懂。");
}
}
package Test28;
//结婚
public class Marriage extends Action {
@Override
public void GetManConclusion(Man concreteElementA) {
System.out.println(concreteElementA.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,感慨道:恋爱游戏终结时,‘有妻徒刑’遥无期。");
}
@Override
public void GetWomanConclusion(Woman concreteElementB) {
System.out.println(concreteElementB.getClass().getSimpleName()+this.getClass().getSimpleName()+"时,欣慰曰:爱情长跑路漫漫,婚姻保险保平安。");
}
}
男人类和女人类
package Test28;
//男人
public class Man extends Person {
@Override
public void Accept(Action visitor) {
visitor.GetManConclusion(this);
}
}
package Test28;
//女人
public class Woman extends Person {
@Override
public void Accept(Action visitor) {
visitor.GetWomanConclusion(this);
}
}
对象结构类
package Test28;
import java.util.ArrayList;
import java.util.List;
//对象结构
public class ObjectStructure {
private List elements = new ArrayList();
//增加
public void Attach(Person element)
{
elements.add(element);
}
//移除
public void Detach(Person element)
{
elements.remove(element);
}
//查看显示
public void Display(Action visitor)
{
for (Person e : elements)
{
e.Accept(visitor);
}
}
}
客户端代码
package Test28;
public class Program {
public static void main(String[] args) {
ObjectStructure o = new ObjectStructure();
o.Attach(new Man());
o.Attach(new Woman());
Success v1 = new Success();
o.Display(v1);
Failing v2 = new Failing();
o.Display(v2);
Amativeness v3 = new Amativeness();
o.Display(v3);
Marriage v4 = new Marriage();
o.Display(v4);
}
}
访问者模式 表示一个作用于某对象结构中的各元素的操作 它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
访问者模式适用于数据结构相对稳定的系统 它把数据结构和作用于结构上的操作之间的耦合解脱开 使得操作集合可以相对自由地演化
访问者模式的目的是要把处理从数据结构分离出来 很多系统可以按照算法和数据结构分开 如果这样的系统有比较稳定的数据结构 又有易于变化的算法的话 使用访问者模式就是比较合适的 因为访问者模式使得算法操作的增加变得容易 反之 如果这样的系统的数据结构对象易于变化 经常要有新的数据对象增加进来 就不适合使用访问者模式
访问者模式的优点就是增加新的操作很容易 因为增加新的操作就意味着增加一个新的访问者 访问者模式将有关的行为集中到一个访问者对象中
缺点其实也就是使增加新的数据结构变得困难了