java中23种设计模式--访问者模式

273 阅读4分钟

兄弟们,老铁们.又到了学习锻炼我们可爱小小大脑的时候了~~~~~ 今天继续来学习设计模式,正所谓一天一个效果不错!! 喝了这碗鸡血,学就完了~~~ 每一个优秀的人,都有一段沉默的时光.那一段时光,是付出了很多努力,忍受孤独和寂寞,不抱怨不诉苦,日后说起时,连自己都能被感动日子。

1.装饰者模式定义

访问者模式顾名思义使用这个模式后就可以在不修改已有程序结构的前提下通过添加额外的"访问者"来完成对已有代码功能的提升.作用于某个对象结构中的各元素操作,它可以在不改变各元素的类的前提下定义作用于这些元素的新操作.

2.装饰着模式结构

在这里插入图片描述

  • 访问者角色(Visitor):为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
  • 具体访问者角色(Concrete Visitor):实现每个由访问者角色(Visitor)声明的操作。
  • 元素角色(Element):定义一个 Accept 操作,它以一个访问者为参数。
  • 具体元素角色(Concrete Element):实现由元素角色提供的 Accept 操作。
  • 对象结构角色(Object Structure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合。

3.实现

一个记账app,自己希望私房钱不让女朋友看到,哈哈哈哈~~~~

账单 Element

//账单   Element
public interface Bill {

  void accept(BookKeeping keeping);

}

支出单 具体元素角色(Concrete Element)

public class ExpenditureBill implements Bill {

  private BigDecimal amount;

  private String item;

  public ExpenditureBill(BigDecimal amount,String item){
    super();
    this.amount = amount;
    this.item = item;
  }

  @Override
  public void accept(BookKeeping keeping) {
    keeping.examine(this);
  }

  public String getItem() {
    return item;
  }

  public BigDecimal getAmount() {
    return amount;
  }
}

收入单 具体元素角色(Concrete Element)

public class IncomeBill implements Bill {

  private BigDecimal amount;

  private String item;

  public IncomeBill(BigDecimal amount,String item){
    super();
    this.amount = amount;
    this.item = item;
  }

  @Override
  public void accept(BookKeeping keeping) {
    keeping.examine(this);
  }

  public BigDecimal getAmount() {
    return amount;
  }

  public String getItem() {
    return item;
  }
}

账本 对象结构角色(Object Structure)

public class Book {

  //单子列表
  private List<Bill> bills = new ArrayList<>();

  public void addBill(Bill bill){
    bills.add(bill);
  }

  public void show(BookKeeping bookKeeping){
    bills.forEach(bill -> bill.accept(bookKeeping));
  }

}

记账app查看者接口 访问者角色

public interface BookKeeping {

  void examine(ExpenditureBill bill);

  void examine(IncomeBill bill);

}

具体访问者

public class MySelf implements BookKeeping {

  private BigDecimal totalIncome;

  private BigDecimal totalExpenditure;

  @Override
  public void examine(ExpenditureBill bill) {
    totalExpenditure = bill.getAmount();
    if (bill.getItem().equals("私房钱")) {
      System.out.println("媳妇不知道我藏了私房钱");
      System.out.println("藏了 " + bill.getAmount() + "元私房钱");
    }else{
      System.out.println(bill.getItem() + " 花费了 " + totalExpenditure + "元");
    }
  }

  @Override
  public void examine(IncomeBill bill) {
    totalIncome = bill.getAmount();

  }

}

具体访问者

public class GirlFriend implements BookKeeping {

  @Override
  public void examine(ExpenditureBill bill) {
    if (bill.getItem().equals("玩游戏")){
      System.out.println("男朋友这个月玩游戏花了 " + bill.getAmount()+ "元,锤死他");
    }
  }

  @Override
  public void examine(IncomeBill bill) {
    System.out.println("男朋友这个月发工资 "+ bill.getAmount() +"元");
  }
}

测试

 public static void main(String[] args) {
    Book book = new Book();
    book.addBill(new ExpenditureBill(new BigDecimal("1000"),"玩游戏"));
    book.addBill(new ExpenditureBill(new BigDecimal("2000"),"房租"));
    book.addBill(new ExpenditureBill(new BigDecimal("500"),"私房钱"));

    book.addBill(new IncomeBill(new BigDecimal("10000"),"工资"));

    MySelf mySelf = new MySelf();
    GirlFriend girlFriend = new GirlFriend();

    book.show(mySelf);
    System.out.println("---------------------------------");
    book.show(girlFriend);
  }

结果

玩游戏 花费了 1000元
房租 花费了 2000元
媳妇不知道我藏了私房钱
藏了 500元私房钱
---------------------------------
男朋友这个月玩游戏花了 1000元,锤死他
男朋友这个月发工资 10000元

4. 优缺点

优点:

  1. 能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  2. 可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
  3. 可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。 缺点:
  4. 不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。
  5. 访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。

5. 适用场景

  1. 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于 其具体类的操作。
  2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
  3. 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。