java23种设计模式(4)-访问者模式

来源:互联网 发布:omega7 知乎 编辑:程序博客网 时间:2024/06/10 23:33

java23种设计模式(4)-访问者模式

    相信大家遇到过这种情形的,对于同一块基本不动的数据,但是有不同的用户来访问,这个时候返回的数据还不是一样的?举个简单的例子,在我们的工作中很多时候是需要对国内的城市和地区做一个城市的列表。或者获取城市的排行榜类似的功能。对于城市这种数据基本很少动的数据。
    数据的内容基本不变,但是呢不同的访问者需要的数据顺序或者是数据结果并不是很一致。
    这个时候就需要我们的设计模式,访问者模式了。首先,我们来看访问者的定义。

访问者模式:访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。


    对于每一个元素而言,我们应该有一个接受访问的方法。对于访问者我们应该有一个访问的方法!这样我们就可以完成一个最重要的目的就将数据结构和访问操作分离开来。
    我们假设有如下一种情况:我们有一个账单类。然后我们的账单一般需要是要给老板看的。但是老板只关心总的收入和支出。还有我们的账单需要给税务部门的审查人员看。他们只关心有没有交税。
对于账单类而言,我们可以有一个简答的接口聚合。
package com.visitors.element;import com.visitors.visitor.IAccountViewerrs;/** * 账单的基类 */public interface IBill {    void accpet(IAccountViewerrs accountViewerrs);}

    然后会有支出和收入两种账单

package com.visitors.element;import com.visitors.visitor.IAccountViewerrs;import lombok.AllArgsConstructor;import lombok.Data;/** * 收入的单子,元素类型的一种 * */@Data@AllArgsConstructorpublic class InCountBill implements IBill{    private double amount;    private String item;    @Override    public void accpet(IAccountViewerrs accountViewerrs) {        accountViewerrs.view(this);    }}
package com.visitors.element;import com.visitors.visitor.IAccountViewerrs;import lombok.AllArgsConstructor;import lombok.Data;@Data@AllArgsConstructorpublic class OutCountBill implements IBill {    private double amount;    private String item;    @Override    public void accpet(IAccountViewerrs accountViewerrs) {        accountViewerrs.view(this);    }}

    同时对于元素而言,我们还应该有一个可以访问所有数据的类。在这里也就是一个账单本.

package com.visitors.father;import com.visitors.element.IBill;import com.visitors.visitor.IAccountViewerrs;import java.util.ArrayList;import java.util.List;public class BillFather {    private List<IBill> bills = new ArrayList<IBill>();    //添加单子    public void addBill(IBill bill) {        bills.add(bill);    }    //供账本的查看者查看账本    public void show(IAccountViewerrs viewer) {        for (IBill bill : bills) {            bill.accpet(viewer);        }    }}

   接下来就是,我们的访问者老板和税务人员了。
    老规矩基类。两个方法一个访问收入一个访问支出。

package com.visitors.visitor;import com.visitors.element.InCountBill;import com.visitors.element.OutCountBill;public interface IAccountViewerrs {    void view(InCountBill bill);    void view(OutCountBill countBill);}

税务人员:

package com.visitors.visitor;import com.visitors.element.InCountBill;import com.visitors.element.OutCountBill;public class CpaViewers implements IAccountViewerrs {    @Override    public void view(OutCountBill bill) {        if (bill.getItem().equals("工资")) {            System.out.println("注会查看账本时,如果单子的消费目的是发工资,则注会会查看有没有交个人所得税。");        }    }    @Override    public void view(InCountBill countBill) {        System.out.println("注会查看账本时,只要是收入,注会都要查看公司交税了没。");    }}

老板:

package com.visitors.visitor;import com.visitors.element.InCountBill;import com.visitors.element.OutCountBill;public class BossViewers implements IAccountViewerrs {    private double inAllCount;    private double outAllCount;    @Override    public void view(InCountBill bill) {        inAllCount += bill.getAmount();    }    @Override    public void view(OutCountBill countBill) {        outAllCount += countBill.getAmount();    }    public double getInAllCount() {        System.out.println("inAllCount = " + inAllCount);        return inAllCount;    }    void setInAllCount(double inAllCount) {        this.inAllCount = inAllCount;    }    public double getOutAllCount() {        System.out.println("outAllCount = " + outAllCount);        return outAllCount;    }    void setOutAllCount(double outAllCount) {        this.outAllCount = outAllCount;    }}

测试一下我们的数据结构和操作分离了吗?

package com.visitors;import com.visitors.element.InCountBill;import com.visitors.element.OutCountBill;import com.visitors.father.BillFather;import com.visitors.visitor.BossViewers;import com.visitors.visitor.CpaViewers;import com.visitors.visitor.IAccountViewerrs;public class Test {    public static void main(String[] args) {        BillFather billFather = new BillFather();        billFather.addBill(new InCountBill(1000, "卖广告位"));        billFather.addBill(new InCountBill(500, "卖产品"));        billFather.addBill(new OutCountBill(1000, "工资"));        billFather.addBill(new OutCountBill(100, "材料"));        IAccountViewerrs boss = new BossViewers();        IAccountViewerrs cpa = new CpaViewers();        billFather.show(boss);        billFather.show(cpa);        ((BossViewers) boss).getInAllCount();    }}

    大概的代码也演示完毕了。那么问题来了我们的访问者模式适合什么样的场景呢???
    首先,我们可以看到为了分离我们的数据和操作。我们将大部分的结果都存放在了访问者类里面。所以我们的数据结构不能够经常的变化,不然的话我们基本上所有的访问者都要从新编码。这是一个很可怕的事情哈!
    主要应用场景有数据结构基本不发生变化的情况。但是不同的角色有不同的访问特性。
    优点:

  1. 符合单一职责
  2. 增加新的访问者方便

     缺点:

  1. 增加新的元素类非常麻烦
  2. 如果改变数据结构,改动量非常大

下面是GitHub地址:https://github.com/yunzhifei/designPatterns.git里面的访问者包就是这次的代码了。不过代码是抄的哈哈!天下代码都可以抄,欢迎fork。都是一些示例的代码!博客是原创的!欢迎转载!

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 a2证扣9分怎么办 a2证扣l分怎么办 b2驾照注销后怎么办 车子转回老家车险怎么办 银行卡过期了钱怎么办 户口迁移证丢失怎么办 考驾照办居住证怎么办 调档函丢了怎么办 车子转籍保险怎么办 驾驶证转走外地怎么办 驾驶证照片坏了怎么办 摩托车不办牌照怎么办 非北京户籍怎么办护照 驾驶证脱审十年怎么办 身份证掉了怎么办异地 驾驶证副业丢了怎么办 驾校不交规费怎么办 驾驶证剩二分了怎么办 扣两个6分怎么办 b2驾照换证有扣分怎么办 卖驾照分被骗怎么办 开车违章12分怎么办 驾驶证分被扣完被交警抓住怎么办 驾照过期后违章怎么办 增驾驾驶证过期怎么办 驾驶证没带事故怎么办 身份证大4岁怎么办 身份证丢了考试怎么办 车险到期没买怎么办 新华保险过期了怎么办 小车保险过期了怎么办 全责方不报保险怎么办 出了事故我全责怎么办 被保险公司追偿怎么办 伪造号牌驾驶证分扣完怎么办 驾驶证挨扣分了怎么办 b2驾照逾期年审怎么办 外地驾照过期几天怎么办 驾校快过期了怎么办 实习期驾照丢了怎么办 车辆违章80分怎么办