访问者模式简单使用

21 篇文章 0 订阅
19 篇文章 0 订阅

前言

“访问者模式是要解决对对象添加新的操作和功能时候,如何尽可能不修改对象的类的一种方法。”我觉得这个解释非常好,我们使用观察者模式的用意就是完成这个目的,以至于添加一个统一的接口accept,来接受一个访问者对象,怎么做到区别对待呢,那就是通过Visitor的不同来处理不同的操作,再怎么解释也不如甩个demo。

适用模式

要用这个模式,其对象必须要结构稳定,当然子类可以增加属性;另一方面如果使用对象不一样执行结果也不相同,那么这个模式很实用。

角色扮演

Visitor:接口或者抽象类,定义一个元素的访问行为,它的参数是可访问的对象,对于访问者不同可以有不同的处理方法;但要求元素要稳定,如果很容易导致这个添加、删除元素,那么不适合这个模式。
ConcreteVisitor:具体的访问者,处理具体行为。
Element:元素接口或者抽象类。定义一个接受访问者的方法,其意义是每一个元素都可以呗访问。
ConcreteElement:具体元素类,提供接受访问方法的具体实现。
ObjectStructure:定义所提到的对象结构,其内部管理元素集合。

demo

抽象一个简单的模型,男生女生对于买手机的要求不太一样,所以对手机的评分也不一样,模拟一个男女去手机店买手机的过程,抽象为双方对手机的评分。
首先我们来定义观察者:
抽象类:

package com.demo.visitor;

/**
 * Created by italkbb on 2017/12/26.
 */

public interface Visitor {
    void visit(IPhone iPhone);
    void visit(AndroidPhone androidPhone);
}

其中用到了Phone的实体,我们先列出来:

package com.demo.visitor;

import java.util.Random;

/**
 * Created by italkbb on 2017/12/26.
 */

public abstract class AbsPhone {
    public String modelName;
    public int money;

    public AbsPhone(String modelName){
        this.modelName = modelName;
        this.money = new Random().nextInt(2000);
    }

    // 定义一个访问方法
    public abstract void accept(Visitor visitor);
}

这个Abs节后相当于Element角色,那么我们可以实现安卓手机和iphone手机:

package com.demo.visitor;

import java.util.Random;

/**
 * Created by italkbb on 2017/12/26.
 */

public class AndroidPhone extends AbsPhone {

    public AndroidPhone(String modelName) {
        super(modelName);
    }

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

    /**
     *
     * 获取手机颜值等级
     * @return
     */
    public int getFaceScore(){
        return new Random().nextInt(5);
    }

    /**
     * 性能分数
     * @return
     */
    public int getPerformance(){
        return new Random().nextInt(5);
    }

}
package com.demo.visitor;

import java.util.Random;

/**
 * Created by italkbb on 2017/12/26.
 */

public class IPhone extends AbsPhone {

    public IPhone(String modelName) {
        super(modelName);
    }

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

    /**
     * 性能分数
     * @return
     */
    public int getPerformance(){
        return new Random().nextInt(5);
    }
}

这都实现了之后,我们要实现Visitor的具体实现:

package com.demo.visitor;

import android.util.Log;

/**
 * Created by italkbb on 2017/12/26.
 */

public class MaleConsumer implements Visitor {
    public final static String CLASSNAME = MaleConsumer.class.getSimpleName();

    @Override
    public void visit(IPhone iPhone) {
        double score = 0;
        if (iPhone.money > 5000){
            score = 3 * 0.6;
        }else{
            score = 5 * 0.6;
        }
        score = score + iPhone.getPerformance() * 0.4;

        Log.v(CLASSNAME,iPhone.modelName + "在男生心里得分:" + score);
    }

    @Override
    public void visit(AndroidPhone androidPhone) {
        double score = 0;
        if (androidPhone.money > 2000){
            score = 3 * 0.3;
        }else{
            score = 5 * 0.3;
        }
        score = score + androidPhone.getPerformance() * 0.7;

        Log.v(CLASSNAME,androidPhone.modelName + "在男生心里得分:" + score);
    }
}
package com.demo.visitor;

import android.util.Log;

/**
 * Created by italkbb on 2017/12/26.
 */

public class FamaleConsumer implements Visitor {
    public final static String CLASSNAME = FamaleConsumer.class.getSimpleName();

    @Override
    public void visit(IPhone iPhone) {
        double score = 0;
        if (iPhone.money > 5000){
            score = 3;
        }else{
            score = 5;
        }
        Log.v(CLASSNAME,iPhone.modelName + "在女生心里得分:" + score);
    }

    @Override
    public void visit(AndroidPhone androidPhone) {
        double score = 0;
        if (androidPhone.money > 2000){
            score = 3 * 0.2;
        }else{
            score = 5 * 0.2;
        }
        score = score + androidPhone.getFaceScore() * 0.8;

        Log.v(CLASSNAME,androidPhone.modelName + "在女生心里得分:" + score);
    }
}

现在我们是有了Visitor和Element类以及实现,我们迫切的需求手机店,不然没啥用:

package com.demo.visitor;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by italkbb on 2017/12/26.
 */

public class PhoneMarket {
    List<AbsPhone> mPhones = new ArrayList<>();

    public PhoneMarket(){
        // 列举市场里面的手机
        mPhones.add(new AndroidPhone("OnePlus 5T"));
        mPhones.add(new IPhone("iphone6s"));
        mPhones.add(new AndroidPhone("Huawei P10"));
        mPhones.add(new IPhone("iphone7"));
        mPhones.add(new AndroidPhone("Pixel XL"));
        mPhones.add(new IPhone("iphoneX"));
        mPhones.add(new AndroidPhone("Mix2"));
    }

    /**
     * 根据考察者来决定手机得分
     * @param visitor
     */
    public void showPhoneLevel(Visitor visitor){
        for (AbsPhone phone:mPhones){
            phone.accept(visitor);
        }
    }
}

写完这些类,我们只差使用了,Client为使用:

package com.demo.visitor;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import teltplay.example.com.kotlindemo.R;

public class VisitorActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_visitor);

        PhoneMarket phoneMarket = new PhoneMarket();
        // 男生看手机
        phoneMarket.showPhoneLevel(new MaleConsumer());

        // 女生看手机
        phoneMarket.showPhoneLevel(new FamaleConsumer());
    }
}

简单的实现了这个Demo,我想这样的话简单的理解访问者模式就简单了。

后记

访问者模式符合单一职责原则,易于扩展, 对于结构稳定的数据使用该模式是个不二之选,这样一说的话缺点也就暴露出来了,当具体元素变更时将导致修改的成本变大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值