从不同角度看同一数据结构-访问者模式

本文介绍了一种不常用的设计模式——访问者模式,并通过一个具体的业绩考核案例展示了如何使用该模式来实现不同角色对同一组数据进行多样化的访问。此模式便于从多个角度观察相同的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

访问者模式是一种复杂的设计模式,使用频率不高,下面举一个公司对员工业绩考核的例子,CEO和CTO对员工的考核标准是不一样的

员工抽象类
public abstract class Staff {
    public String name;
    public int kpi;
    public Staff(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }

    public abstract void accept(Visitor visitor);
}

基类中只有员工的公共属性,这里是姓名和kpi

员工具体类
  1. 工程师类
public class Engineer extends Staff {
    public Engineer(String name) {
        super(name);
    }

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

    public int getCodeLines() {
        return new Random().nextInt(10*10000);
    }
}
  1. 产品经理类
public class Manager extends Staff {
    public Manager(String name) {
        super(name);
    }

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

    public int getProducts() {
        return new Random().nextInt(10);
    }
}

在具体类中加入独特的属性,这样访问者访问时就可以区别对待

抽象访问者类
public interface Visitor {
    void visit(Engineer engineer);
    void visit(Manager manager);
}
具体访问类
  1. CEO:只关心员工的姓名和KPI
public class CEO implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("Engineer:"+ engineer.name + ", kpi: " +engineer.kpi);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("Manager: "+ manager.name + ", kpi: "+manager.kpi);
    }
}
  1. CTO:根据岗位的不同关心不同的技术指标
public class CTO implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("Engineer: " + engineer.name +", code: " + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("Manager: " + manager.name + ", product: "+ manager.getProducts());
    }
}

具体示例如下

public class Main {
    public static void main(String[] args) {
        BusinessReport businessReport = new BusinessReport();
        System.out.println("======CEO=====");
        businessReport.showReport(new CEO());
        System.out.println("\n=====CTO=====");
        businessReport.showReport(new CTO());
    }
}

结果

捕获.PNG

访问者模式可以很方便地添加访问者,方便地从多种角度观察同一种数据结构

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
<think>嗯,用户想比较客户端-服务器架构和发布-订阅模式的异同。这个问题挺专业的,可能需要从系统设计的角度来分析。用户可能是开发者或架构师,正在为某个项目选择通信模型。 先回顾基本概念。客户端-服务器架构(C/S)应该是最经典的网络模型了,客户端主动发起请求,服务器被动响应。就像去餐厅点菜,顾客(客户端)说要什么,厨房(服务器)做好了端上来。而发布-订阅模式更像是订报纸——出版社(发布者)把报纸印好,邮局(代理)负责投递,订户(订阅者)在家就能收到。 用户提供的几个引用很有价值。引用[1]和[2]正好讨论这两种模式,引用[3]提到Redis对订阅命令的特殊处理,引用[4]则说明消息体的通用结构。这些材料能帮助构建对比框架。 需要特别注意几个关键差异点:首先是通信方向,C/S是双向请求-响应,Pub/Sub是单向广播;然后是耦合度,Pub/Sub通过代理解耦更彻底;最后是状态管理,服务器需要维护客户端状态,而代理通常不需要。 联系方面其实很有趣。引用[1]指出Pub/Sub本质是观察者模式的升级,而C/S架构里其实也能实现简单的观察者模式。比如服务器推数据给客户端时,底层还是依赖C/S的TCP连接。Redis的案例(引用[3])就很典型——它用C/S架构传输Pub/Sub命令,说明两种模式可以嵌套使用。 用户可能还想知道实际选型建议。游戏服务器(引用[1])常用Pub/Sub处理广播消息,但登录支付必须用C/S保证可靠性。物联网场景更明显:传感器数据用Pub/Sub推送,设备控制用C/S请求响应。 最后生成的三个问题应该能覆盖用户可能的延伸思考:性能对比帮助选型,组合应用探讨实践,适用场景决定方向。特别是组合应用那个问题,用户如果正在设计复杂系统应该会感兴趣。</think>以下是客户端-服务器架构(C/S)与发布-订阅模式(Pub/Sub)的详细对比分析,结合其核心特性、应用场景和内在联系: --- ### **一、核心区别** | **维度** | **客户端-服务器架构** | **发布-订阅模式** | |------------------|------------------------------------------|------------------------------------------| | **通信方向** | 双向同步:客户端主动请求,服务器被动响应 | 单向异步:发布者发送消息,订阅者被动接收 | | **耦合性** | 紧耦合:客户端需明确知道服务器地址和接口 | **松耦合**:发布者/订阅者通过代理(如消息队列)解耦 | | **连接关系** | 1:1 或 1:N(如多个客户端访问同一服务器) | N:M(多个发布者向多个订阅者广播消息) | | **状态管理** | 服务器需维护会话状态(如用户登录) | 代理通常无状态,消息传递后即解除关联 | | **典型协议** | HTTP(S)、TCP、RPC | MQTT、AMQP、Redis Pub/Sub | --- ### **二、核心联系** 1. **底层依赖关系** Pub/Sub 的实现往往依赖 C/S 架构。例如: - Redis Pub/Sub 中,客户端通过 TCP 连接服务器订阅频道 [^3]。 - MQTT 代理(如 Mosquitto)本质是服务器,客户端通过连接代理实现订阅。 2. **功能互补性** C/S 处理需强一致性的操作(如支付),Pub/Sub 处理事件广播(如实时通知)。 > 示例:电商系统中,订单支付用 C/S 接口,而库存更新通知用 Pub/Sub 广播 [^4]。 3. **设计模式演进** Pub/Sub 是观察者模式的扩展,通过引入**代理层**(如消息队列)实现更高解耦 [^1]。 > 引用[1]指出:*"发布订阅模式是最常用的一种观察者模式的实现,从解耦和重用角度看更优于典型观察者模式。"* --- ### **三、典型应用场景** | **模式** | **适用场景** | **案例** | |------------------|------------------------------------------|----------------------------------------| | **C/S架构** | 需精准响应的操作 | 用户登录、数据库读写、API 调用 | | **Pub/Sub** | 事件驱动、实时广播、系统解耦 | 聊天室消息推送、IoT设备状态同步、日志收集 | > **场景对比**: > - 游戏服务器中,玩家移动(C/S)需低延迟响应,而全服公告(Pub/Sub)可异步广播 [^2]。 > - 金融系统中,交易下单(C/S)需强一致性,行情数据推送(Pub/Sub)可高并发分发。 --- ### **四、协作模式示例** ```plaintext +------------------+ +------------------+ | 发布者 (Publisher) | --消息--> | 消息代理 (Broker) | +------------------+ +---------+--------+ | 路由分发 v +------------------+ +------------------+ | 订阅者 (Subscriber) | <--数据-- | 订阅者 (Subscriber) | +------------------+ +------------------+ ``` > 代理层(如 Kafka、RabbitMQ)解耦发布者与订阅者,支持消息持久化、重试等特性 [^4]。 --- ### **五、关键选择建议** - **选 C/S 当**:需严格事务控制、低延迟响应、点对点通信。 - **选 Pub/Sub 当**:系统需解耦、支持动态扩缩容、处理海量异步事件。 - **混合使用**:多数系统组合两者(如微服务中:C/S 调用 + Pub/Sub 事件总线)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值