设计模式—访问者模式

这篇具有很好参考价值的文章主要介绍了设计模式—访问者模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 需求:店铺采购了一批水果(苹果及橘子),现在市场监督局来店里检查过期的水果。

public class Fruit {

    private String name;
    private Date pickDate;

    public Fruit(String name, Date pickDate) {
        this.name = name;
        this.pickDate = pickDate;
    }

    public String getName() {
        return name;
    }

    public Date getPickDate() {
        return pickDate;
    }

    @Override
    public String toString() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        return "{" +
                "name='" + name + '\'' +
                ", 采摘日期=" + simpleDateFormat.format(pickDate) +
                '}';
    }
}

public class Apple extends Fruit{

    public Apple(String name, Date pickDate) {
        super(name, pickDate);
    }
    
}

public class Orange extends Fruit{
    public Orange(String name, Date pickDate) {
        super(name, pickDate);
    }
}

public class FruitShop  {

    private final String name;

    public FruitShop(String name) {
        this.name = name;
    }

    private final List<Fruit> fruitList = new ArrayList<>();

    public List<Fruit> getFruitList() {
        return fruitList;
    }

    public String getName() {
        return name;
    }

}

public class FruitMarket {

    public static void main(String[] args) throws ParseException {
        FruitShop myShop = new FruitShop("老果农");
        purchaseFruit(myShop);
        expCheck("市场监督局",myShop); //市场监督局检查过期水果:苹果过期时间5天,橘子过期时间10天
        expCheck("城管",myShop); //城管检查过期水果:苹果过期时间3天,橘子过期时间6天
        newArrival(myShop);//新品上市水果
    }

    // 采购水果
    public static void purchaseFruit(FruitShop shop) throws ParseException {
        List<Fruit> fruitList = shop.getFruitList();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        fruitList.add(new Apple("富士康",simpleDateFormat.parse("2023-06-21 12:00")));
        fruitList.add(new Orange("赣南脐橙", simpleDateFormat.parse("2023-05-25 18:00")));
        fruitList.add(new Orange("韶关帝王橘", simpleDateFormat.parse("2023-6-18 21:00")));
        fruitList.add(new Apple("王掌柜",simpleDateFormat.parse("2023-06-11 12:00")));
    }

    // 过期检查
    public static void expCheck(String development,FruitShop shop) {
        int appleExpDay = 0, orangeExpDay = 0;
        if ("市场监督局".equals(development)) {
            appleExpDay = 5;
            orangeExpDay = 10;
        } else if ("城管".equals(development)) {
            appleExpDay = 2;
            orangeExpDay = 4;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE,-appleExpDay);
        Date appleExpDate = calendar.getTime();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE,-orangeExpDay);
        Date orangeExpDate = calendar.getTime();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        System.out.println(development + "检查 苹果过期天数:" + appleExpDay + "  橘子过期天数:" + orangeExpDay + "  检查时间:" + dateFormat.format(new Date()) + " " + shop.getName());
        for (Fruit fruit : shop.getFruitList()) {
            boolean exp = false;
            if (fruit instanceof Apple) {
                if (appleExpDate.after(fruit.getPickDate())) exp = true;
            } else if (fruit instanceof Orange) {
                if (orangeExpDate.after(fruit.getPickDate())) exp = true;
            }
            if (exp) System.out.println(fruit + "  过期! ");
        }
        System.out.println("-------");
    }
   
}

如果此时再添加一个操作:找出新品上市的水果。

// 新品上市 苹果为2023-06-20 后采摘, 橘子为2023-06-21后采摘
    public static void newArrival(FruitShop shop) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date appleNewDate = simpleDateFormat.parse("2023-06-20");
        Date orangeNewDate = simpleDateFormat.parse("2023-06-21");
        for (Fruit fruit : shop.getFruitList()) {
            boolean isNew = false;
            if (fruit instanceof Apple) {
                if(appleNewDate.before(fruit.getPickDate())) isNew = true;
            } else if (fruit instanceof  Orange) {
                if(orangeNewDate.before(fruit.getPickDate())) isNew= true;
            }
            if (isNew) System.out.println(fruit.getName() + " 新品上市");
        }
    }

上述代码中,FruitMarket为应付新增操作,增加了相应的方法来满足要求,但这样破坏了FruitMarket的结构。

访问者模式

本质是将数据结构和数据操作分离,通过定义一个访问者对象,实现对数据结构中各个元素的访问和处理,从而达到解耦和灵活性的目的。

设计模式—访问者模式

图 访问者UML

Visitor 抽象访问者

为ObjectStructure对象结构中的每一个Element都声明一个Visit操作。

ConcreteVisitor具体访问者

Visitor的实现,实现要真正被添加到对象结构中的功能。

ObjectStructure 对象结构

通常包含多个被访问的对象,可以是一个复合或是一个集合。

Element 抽象元素

为Visitor声明一个accept方法,实现元素与访问者的绑定。

ConcreteElement 具体元素

对象结构体中具体的对象,是被访问的对象。

/**
 * 水果元素抽象类
 */
public abstract class FruitElement {

    private String name;
    private Date pickDate;

    public FruitElement(String name, Date pickDate) {
        this.name = name;
        this.pickDate = pickDate;
    }

    public String getName() {
        return name;
    }

    public Date getPickDate() {
        return pickDate;
    }

    public abstract void accept(Visitor visitor);

    @Override
    public String toString() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        return "{" +
                "name='" + name + '\'' +
                ", 采摘日期=" + simpleDateFormat.format(pickDate) +
                '}';
    }

}
public class AppleElement extends FruitElement{

    public AppleElement(String name, Date pickDate) {
        super(name, pickDate);
    }

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

}

public class OrangeElement extends FruitElement{

    public OrangeElement(String name, Date pickDate) {
        super(name, pickDate);
    }

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

}
/**
 * 访问者
 */
public interface Visitor {

    void visit(AppleElement apple);

    void visit(OrangeElement orange);

}

/**
 * 政府检查部门
 */
public class DevelopmentVisitor implements Visitor{

    private final int appleExpDay;

    private final int orangeExpDay;

    public DevelopmentVisitor(String name, int appleExpDay, int orangeExpDay) {
        this.appleExpDay = appleExpDay;
        this.orangeExpDay = orangeExpDay;
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        System.out.println(name + " 检查过期水果, 苹果过期天数:" + appleExpDay + ",橘子过期天数:" +
                orangeExpDay + " 检查时间:" + dateFormat.format(new Date()));
    }

    @Override
    public void visit(AppleElement apple) {
        expCheck(apple, appleExpDay);
    }

    @Override
    public void visit(OrangeElement orange) {
        expCheck(orange,orangeExpDay);
    }

    private void expCheck(FruitElement fruit,int expDay) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE,-appleExpDay);
        Date appleExpDate = calendar.getTime();
        if (appleExpDate.after(fruit.getPickDate())) {
            System.out.println(fruit.getName() + " 过期!");
        }
    }
}


/**
 * 新品上市检查
 */
public class NewArrivalVisitor implements Visitor {

    private final Date appleNewDate;

    private final Date orangeNewDate;

    public NewArrivalVisitor(Date appleNewDate, Date orangeNewDate) {
        this.appleNewDate = appleNewDate;
        this.orangeNewDate = orangeNewDate;
        System.out.println("新品上市检查");
    }

    @Override
    public void visit(AppleElement apple) {
        if (appleNewDate.before(apple.getPickDate())) {
            System.out.println(apple.getName() + " 新品上市");
        }
    }

    @Override
    public void visit(OrangeElement orange) {
        if (orangeNewDate.before(orange.getPickDate())) {
            System.out.println(orange.getName() + " 新品上市");
        }
    }
}
/**
 * 水果店结构
 */
public class FruitShopStructure {

    private final List<FruitElement> fruitList = new ArrayList<>();

    public List<FruitElement> getFruitList() {
        return fruitList;
    }

}
public class FruitMarket2 {

    public static void main(String[] args) throws ParseException {
        //新开一家水果店
        FruitShopStructure shop = new FruitShopStructure();
        purchaseFruit(shop);

        System.out.println("------------------------------");
        //市场监督局来检查是否存在过期水果
        DevelopmentVisitor devVisitor1 = new DevelopmentVisitor("市场监督局", 5, 10);
        for (FruitElement element : shop.getFruitList()) {
            element.accept(devVisitor1);
        }
        System.out.println("------------------------------");
        //农业局来检查是否存在过期水果
        DevelopmentVisitor devVisitor2 = new DevelopmentVisitor("农业局", 2, 4);
        for (FruitElement element : shop.getFruitList()) {
            element.accept(devVisitor2);
        }
        System.out.println("------------------------------");
        //检查新品上市
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        NewArrivalVisitor newArrivalVisitor = new NewArrivalVisitor(simpleDateFormat.parse("2023-06-20"), simpleDateFormat.parse("2023-06-21"));
        for (FruitElement element : shop.getFruitList()) {
            element.accept(newArrivalVisitor);
        }
    }

    // 采购水果
    public static void purchaseFruit(FruitShopStructure shop) throws ParseException {
        List<FruitElement> fruitList = shop.getFruitList();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        fruitList.add(new AppleElement("富士康",simpleDateFormat.parse("2023-06-21 12:00")));
        fruitList.add(new OrangeElement("赣南脐橙", simpleDateFormat.parse("2023-05-25 18:00")));
        fruitList.add(new OrangeElement("韶关帝王橘", simpleDateFormat.parse("2023-6-18 21:00")));
        fruitList.add(new AppleElement("王掌柜",simpleDateFormat.parse("2023-06-11 12:00")));
    }
}

设计模式—访问者模式

图 运行结果 

以上代码是用访问者模式实现文章开头处的需求。

优点

  1. 好的扩展性,能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  2. 好的复用性,可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
  3. 分离无关行为,通过访问者来分离无关的行为,把相关行为封装在一起,构成一个访问者,这样每个访问者的功能都比较单一。

缺点

1)对象结构变化很困难,不适用于对象结构中的类经常变化的情况,当对象结构发生改变时,访问者的接口及实现都要做相应改变。

2)破坏封装,访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructure,这破坏了对象的封装性。

应用场景

1)需要对一个复杂的数据结构进行操作,并且这些操作可能需要根据不同的元素类型进行变化。

2)当数据结构中的元素种类相对稳定,但可能需要新增一些新的操作时。文章来源地址https://www.toymoban.com/news/detail-498370.html

到了这里,关于设计模式—访问者模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式之访问者模式(上)

    访问者模式 1)概述 1.概念 访问者模式包含 访问者 和 被访问元素 两个主要组成部分。 处方单中的各种药品信息就是 被访问的元素 ,而划价人员和药房工作人员就是 访问者 ,被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。 被访问元素

    2024年04月25日
    浏览(41)
  • Java设计模式-访问者模式

    在软件开发领域中,设计模式是解决常见问题的经典方法。其中,访问者模式是一种强大且灵活的设计模式,用于处理对象结构中的元素,并根据不同的访问者实现不同的操作。 访问者模式是一种行为型设计模式,它允许你在不改变元素类的前提下定义新的操作。该模式将算

    2024年02月06日
    浏览(54)
  • js设计模式:访问者模式

    将操作方法封装在一个访问者对象中,而不是封装在每个被访问对象当中。 访问者对象可以通过调用被访问者的接口,用来操作被访问者。

    2024年02月22日
    浏览(71)
  • 设计模式:访问者模式(C++实现)

    访问者模式通过将对元素的操作与元素本身分离,使得可以在不修改元素类的情况下定义新的操作。 运行结果: 在上述代码中,Visitor是访问者接口,定义了访问具体元素的方法。Element是元素接口,定义了接受访问者访问的方法。ConcreteElementA和ConcreteElementB是具体元素类,实

    2024年02月07日
    浏览(53)
  • 03-JAVA设计模式-访问者模式

    访问者模式(Visitor Pattern)是软件设计模式中的一种行为模式,它用于将数据结构中的元素与操作这些元素的操作解耦。这种模式使得可以在不修改数据结构的情况下添加新的操作。 在访问者模式中,我们定义了两个主要角色: 访问者(Visitor): 这个接口声明了一个访问元

    2024年04月29日
    浏览(47)
  • 设计模式(二十三)访问者

    表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式 访问者模式是一种较为复杂的行为型模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素

    2024年02月19日
    浏览(39)
  • 【设计模式与范式:行为型】69 | 访问者模式(下):为什么支持双分派的语言不需要访问者模式?

    上一节课中,我们学习了访问者模式的原理和实现,并且还原了访问者模式诞生的思维过程。总体上来讲,这个模式的代码实现比较难,所以应用场景并不多。从应用开发的角度来说,它的确不是我们学习的重点。 不过,我们前面反复说过,学习我的专栏,并不只是让你掌握

    2024年02月10日
    浏览(48)
  • 笨蛋学设计模式行为型模式-访问者模式【21】

    8.8.1概念 ​ 访问者模式是一种将操作逻辑与对象结构分离的方法,使得操作可以独立变化,操作逻辑被封装在独立的访问者类中,并在被访问的元素类中提供接受访问者的方法,而不是直接嵌入到数据结构中的对象中。 8.8.2场景 ​ 我们可以将一个购物商场中的商品类作为元

    2024年01月23日
    浏览(53)
  • 瑞_23种设计模式_访问者模式

    🙊 前言:本文章为瑞_系列专栏之《23种设计模式》的访问者模式篇。本文中的部分图和概念等资料,来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》,特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及

    2024年04月15日
    浏览(48)
  • 软件设计模式系列之二十五——访问者模式

    访问者模式(Visitor Pattern)是一种强大的行为型设计模式,它允许你在不改变被访问对象的类的前提下,定义新的操作和行为。本文将详细介绍访问者模式,包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景、优缺点、类似模式以及最后的小结。 访问者

    2024年02月08日
    浏览(86)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包