• 【软考】设计模式之访问者模式


    1. 说明
    • 1.访问者设计模式(Visitor Design Pattern)是一种常见的软件设计模式
    • 2.属于行为型设计模式,行为型对象模式
    • 3.目的:分离数据结构与数据操作,在不改变元素数据结构的情况下,进行添加元素操作
    2. 应用场景
    • 1.类的结构改变较少,但经常要增加新的基于该结构的操作
    • 2.需要对某一对象结构的对象进行很多不同的并且不相关的操作,而需要避免让这些操作污染这些对象的类,也不希望在新增操作时修改这些类
    3. 结构图

    在这里插入图片描述

    4. 构成
    • 1.访问者模式由抽象访问者、具体访问者、抽象元素、具体元素、对象结构等角色构成
    • 2.抽象访问者(Visitor):定义访问具体元素的接口,为每个具体元素类声明一个Visit操作,该操作的参数类型标识了被访问的具体元素
    • 3.具体访问者(ConcreteVisitor):实现抽象访问者中声明的各个Visit操作
    • 4.抽象元素(Element):声明一个包含接受操作Accept()的接口,Accept()参数为被接受访问者
    • 5.具体元素(ConcreteElement):实现一个访问者为参数的Accept操作
    • 6.对象结构(ObjectStructure):包含抽象元素的容器,提供让访问者对象遍历容器中所有元素的方法(List、Set、Map等)
    5. java示例
    5.1 喂动物
    5.1.1 抽象访问者
    • 1.一个抽象访问者接口
    • 2.定义访问具体元素的方法feed,为每个具体元素类声明一个喂养的方法,喂狗和喂猫,喂养操作的参数类型标识了被访问的具体元素为狗和猫
    package com.learning.visitor;
    /**
    * 抽象访问者
    */
    public interface Person {
        public void feed(Dog dog);
    
        public void feed(Cat cat);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    5.1.2 具体访问者
    • 1.具体访问者(ConcreteVisitor):实现抽象访问者中声明的各个Visit操作
    • 2.自家主人实现抽象访问者中声明的喂狗、喂猫操作
    • 3.其他人实现抽象访问者中声明的喂狗、喂猫操作
    package com.learning.visitor;
    
    /**
     *  自家主人
     */
    public class Owner implements Person{
        @Override
        public void feed(Cat cat) {
            System.out.println("主人喂食猫");
        }
    
        @Override
        public void feed(Dog dog) {
            System.out.println("主人喂食狗");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    package com.learning.visitor;
    
    /**
     * 其他人
     */
    public class Someone implements Person{
    
        @Override
        public void feed(Dog dog) {
            System.out.println("其他人喂食狗");
        }
    
        @Override
        public void feed(Cat cat) {
            System.out.println("其他人喂食猫");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    5.1.3 抽象元素
    • 1.定一个动物接口,声明一个接收一个人的方法
    • 2.表明是谁喂,参数人为被接受访问者
    package com.learning.visitor;
    /**
    * 抽象元素  动物
    */
    public interface Animal {
        void accept(Person person);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    5.1.4 具体元素
    • 1.实现accept操作,参数是一个访问者
    package com.learning.visitor;
    /**
    * 狗
    */
    public class Dog implements Animal{
        @Override
        public void accept(Person person) {
            person.feed(this);
            System.out.println("汪汪汪");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    package com.learning.visitor;
    
    /**
     * 猫
     */
    public class Cat implements Animal{
        @Override
        public void accept(Person person) {
            person.feed(this);
            System.out.println("喵喵喵");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    5.1.5 对象结构
    • 1.包含抽象元素的容器,提供让访问者对象遍历容器中所有元素的方法(List、Set、Map等)
    • 2.通过add方法,将具体的元素狗和猫放进List中
    • 3.提供遍历List中所有元素的方法action
    package com.learning.visitor;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 家
     */
    public class Home {
        // 声明一个集合对象,用来存储元素对象
        private List animalList = new ArrayList<>();
    
        // 添加元素功能
        public void add(Animal animal){
            animalList.add(animal);
        }
    
        public void action(Person person){
            //遍历集合,获取每一个元素,让访问者访问每一个元素
            for(Animal animal : animalList){
                animal.accept(person);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    5.1.6 客户端类
    package com.learning.visitor;
    
    /**
     * 客户端
     */
    public class Client {
        public static void main(String[] args) {
            //创建home对象
            Home home = new Home();
            // 添加元素到home对象中
            home.add(new Dog());
            home.add(new Cat());
    
            //创建主人对象
            Owner owner = new Owner();
            // 主人喂猫
            home.action(owner);
    
            //创建其他人对象
            Someone someone = new Someone();
            //其他人喂食
            home.action(someone);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    5.1.7 结果示例

    在这里插入图片描述

    5.2 超市销售系统
    5.2.1 业务场景
    • 1.假设现在要创建一个简单的超市销售系统,顾客将毛巾、饼干、酸奶等物品(Item)加入购物车(Shopping_Cart),在收银台(Checkout)人工(Manual)或自动(Auto)地将购物车中每个物品的价格汇总到总价格后结账。
    5.2.2 业务需求类图

    在这里插入图片描述

    5.2.3 抽象访问者
    • 1.该场景下,抽象访问者为收银台Checkout
    • 2.定义访问具体元素的方法checkout,为每个具体元素类声明一个结账的方法,结账操作的参数类型标识了被访问的具体元素为毛巾、饼干和酸奶等
    package com.learning.visitor.shop;
    
    // 结账接口
    interface Checkout {
        // 结账毛巾
        void checkout(Towel towel);
    
        // 结账饼干
        void checkout(Cookie cookie);
    
        // 结账酸奶
        void checkout(Yogurt yogurt);
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    5.2.4 具体访问者
    • 1.具体访问者(ConcreteVisitor):实现抽象访问者中声明的各个结账操作
    • 2.人工结账实现抽象访问者中声明的结账毛巾、饼干、酸奶操作
    • 3.自动结账实现抽象访问者中声明的结账毛巾、饼干、酸奶操作
    package com.learning.visitor.shop;
    
    // 人工结账类
    public class ManualCheckout implements Checkout {
    
        @Override
        public void checkout(Towel towel) {
            System.out.println("人工结账毛巾");
        }
    
        @Override
        public void checkout(Cookie cookie) {
            System.out.println("人工结账饼干");
        }
    
        @Override
        public void checkout(Yogurt yogurt) {
            System.out.println("人工结账酸奶");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    package com.learning.visitor.shop;
    
    // 自动结账类
    public class AutoCheckout implements Checkout {
        @Override
        public void checkout(Towel towel) {
            System.out.println("自动结账毛巾");
        }
    
        @Override
        public void checkout(Cookie cookie) {
            System.out.println("自动结账饼干");
        }
    
        @Override
        public void checkout(Yogurt yogurt) {
            System.out.println("自动结账酸奶");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    5.2.5 抽象元素
    • 1.定一个物品接口,声明一个接收一个结账方式的方法
    • 2.表明是哪种方式结账,其中方法的参数即收银台为被接受访问者
     package com.learning.visitor.shop;
    
    // 物品接口
    public interface Item {
    
        void accept(Checkout checkout);
        double getPrice();
        String getName();
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    5.2.6 具体元素
    • 1.实现accept操作,参数是一个访问者即收银台
    package com.learning.visitor.shop;
    
    /**
     * 毛巾类
     */
    public class Towel implements Item{
    
        @Override
        public void accept(Checkout checkout) {
            checkout.checkout(this);
        }
    
        @Override
        public double getPrice() {
            return 5.99;
        }
    
        @Override
        public String getName() {
            return "毛巾";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    package com.learning.visitor.shop;
    
    /**
     * 饼干
     */
    public class Cookie implements Item {
        @Override
        public void accept(Checkout checkout) {
            checkout.checkout(this);
        }
    
        @Override
        public double getPrice() {
            return 2.99;
        }
    
        @Override
        public String getName() {
            return "饼干";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    package com.learning.visitor.shop;
    
    /**
     * 酸奶
     */
    public class Yogurt implements Item {
        @Override
        public void accept(Checkout checkout) {
            checkout.checkout(this);
        }
    
        @Override
        public double getPrice() {
            return 1.99;
        }
    
        @Override
        public String getName() {
            return "酸奶";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    5.2.7 对象结构
    • 1.包含抽象元素的容器,提供让访问者对象遍历容器中所有元素的方法(List、Set、Map等)
    • 2.通过add方法,将具体的元素毛巾、饼干、酸奶放进List中
    • 3.提供遍历List中所有元素的方法action
    package com.learning.visitor.shop;
    
    import java.util.ArrayList;
    import java.util.List;  
      
    // 购物车类  
    public class ShoppingCart {
        private List items = new ArrayList<>();  
      
        public void addItem(Item item) {  
            items.add(item);  
        }
    
        /**
         * 结账action
         * @param checkout
         */
        public void action(Checkout checkout) {
            for (Item item : items) {
                item.accept(checkout);
            }
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    5.2.8 客户端类
    package com.learning.visitor.shop;
    
    /**
     * 超市销售系统
     */
    public class SupermarketSystem {
        public static void main(String[] args) {  
            // 创建物品  
            Item towel = new Towel();  
            Item cookie = new Cookie();
            Item yogurt = new Yogurt();  
      
            // 创建购物车并添加物品  
            ShoppingCart cart = new ShoppingCart();  
            cart.addItem(towel);  
            cart.addItem(cookie);
            cart.addItem(yogurt);  
      
            // 使用人工结账  
            ManualCheckout manualCheckout = new ManualCheckout();
            cart.action(manualCheckout);
      
            // 使用自动结账  
            AutoCheckout autoCheckout = new AutoCheckout();  
            cart.action(autoCheckout);
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    5.2.9 结果示例

    在这里插入图片描述

    5.2.10 改进
    • 1.结账接口可以把购物车作为参数进行结账
    // 结账接口  
    interface Checkout {  
        void checkout(ShoppingCart cart);  
    }  
    
    • 1
    • 2
    • 3
    • 4
    // 人工结账类  
    class ManualCheckout implements Checkout {  
        @Override  
        public void checkout(ShoppingCart cart) {  
            System.out.println("Manual Checkout");  
            System.out.println("Total price: " + cart.getTotalPrice());  
            // 在这里执行人工结账的逻辑,比如接收现金或刷卡  
        }  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    // 自动结账类  
    class AutoCheckout implements Checkout {  
        @Override  
        public void checkout(ShoppingCart cart) {  
            System.out.println("Auto Checkout");  
            System.out.println("Total price: " + cart.getTotalPrice());  
            // 在这里执行自动结账的逻辑,比如扫描条形码或使用移动支付  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    Java学习笔记5.2.1 List接口 - ArrayList类
    【微信小程序】6天精准入门(第2天:小程序的视图层、逻辑层、事件系统及页面生命周期)
    包裹细胞膜的磁性纳米微载体/负载斑蝥素的巨噬细胞膜包封金属有机框架纳米颗粒的研究
    C++ freopen函数用法详解
    01-shell编程规范与变量
    TypeScript 从入门到进阶之基础篇(一) ts类型篇
    如何缩减layout电路面积?减少晶体管的数量——以全加器为例【VLSI】
    pip的基本命令和使用
    排查服务器异常流量保姆级教程
    M1 Mac:支持 USB-C,但不完全支持
  • 原文地址:https://blog.csdn.net/qq_32088869/article/details/136382052