V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
csfreshman
V2EX  ›  程序员

面试题讨论,类设计

  •  
  •   csfreshman · 49 天前 · 2586 次点击
    这是一个创建于 49 天前的主题,其中的信息可能已经有所发展或是发生改变。

    虾皮面经中看到一道题: 如果要实现一个聊天室的逻辑,有 room 和 user 两个类,而 room 设置有一个门,而且有“主人的设定,只有主人才能开门和关门。请问开门和关门的方法,你会放到 room 类还是 user 类中实现 ?为什么?

    各位大佬,如果你面试时遇到会怎么回答。 我的想法是: 放在 room 类,room 类中保存房间主人,user 用户如果是主人可以开门或关门,本一菜鸡没看懂这题到底要考察啥?跪求各位大佬指点 讨论。

    31 条回复    2021-04-26 17:19:52 +08:00
    RedisMasterNode
        1
    RedisMasterNode   49 天前
    哈哈哈 我猜这是 chatbot 团队的面试官

    room 类+1
    raaaaaar
        2
    raaaaaar   49 天前 via Android
    room,因为门和 room 是一一对应的,是 room 的一种功能。而 room 相关的信息都应该封装在 room 类日,这样才能根据不同的 user 表现出不同的功能,不仅仅是门
    raaaaaar
        3
    raaaaaar   49 天前 via Android
    比如说 room 加一个 owner 的属性,当 user 调用 room 时就比较下,根据结果走不同的分支
    MoHen9
        4
    MoHen9   49 天前 via Android
    菜鸡一枚,说说我的看法,我也 get 不到想问什么,可能是对面向对象思想的考察,首先房间有门,门有开关的动作,这是与现实世界的对应,符合基本逻辑,房间有管理员,可以执行开关门的动作,谁是管理员谁就拥有开关门的权限。这样门和房间主人是关联关系,房间主人可以有一个也可以有多个。

    如果门或者动作放到 User 上,一个人有多个门时,还得找这些门和对应房间的关系,一个门有多个主人时,啊,什么鬼👻,打出去,乱棍打出去。。。🌚🌚
    BeautifulSoap
        5
    BeautifulSoap   49 天前
    开门关门的意思是能否允许其他用户进入?
    第一直觉是 room 类实现具体怎么开门(因为开门的具体逻辑可能很复杂,交给 user 类的话相当于将 room 类内部详细的结构给暴露了),room 通过对外暴露一个开门关门的接口接受认证信息 or 鉴权,用户直接调用,这样用户只需要持有各个房间的钥匙(认证信息 or 鉴权信息)就行了

    如果想搞不同开门方式,或者开门后限制不同人,或复杂的鉴权的话,可能将相关逻辑独立成单独的类比较好。但这个问题只有两个类,倒也不好展开
    huijiewei
        6
    huijiewei   49 天前
    这个里面需求也不说

    要我就按照最复杂的来搞

    请个保安
    nuistzhou
        7
    nuistzhou   49 天前 via iPhone
    很简单吧,就是类的设计吧。我也选开关门的 method 放在 room 里,user 可以有个 type 为字典的属性,开关门的 method 验证该用户的这个字典里是否有这个 room 的 key,来鉴权。
    charlie21
        8
    charlie21   49 天前
    左手右手一个慢动作 右手左手慢动作重播
    先写一个 room interface 这是它需要的
    psx2019
        9
    psx2019   49 天前
    ```java
    public class Room{
    String roomId;
    String key;
    Boolean openStatus;
    public Room() {
    this.roomId = UUID.randomUUID().toString();
    this.key = UUID.randomUUID().toString();
    this.openStatus = false;
    }

    public String getRoomId() {
    return roomId;
    }

    public String getKey() {
    return key;
    }

    public Boolean getOpenStatus() {
    return openStatus;
    }

    public void openOrClose(String key) {
    if (this.key.equals(key)) {
    this.openStatus = !this.openStatus;
    }
    }
    }

    public class User {
    String name;
    Map<String, String> roomKeys =new HashMap<String, String>();
    Map<String, Room> rooms =new HashMap<String, Room>();

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

    public String getName() {
    return name;
    }

    public Map<String, String> getRoomKeys() {
    return roomKeys;
    }

    public Map<String, Room> getRooms() {
    return rooms;
    }
    }

    ```
    winnerczwx
        10
    winnerczwx   49 天前   ❤️ 1
    同菜鸡

    猜测一下面试官想考啥吧

    我猜他想考的是 room 的权限设计, room owner 不仅仅可以开关门, 可能后期会加入踢人, 拉人等功能

    如果把权限放在 user 里, 感觉就很乱, 一个 user 类 又要存用户信息, 又要存房间权限信息, 这不符合单一职责原则, 而且随着业务需求增加, 维护成本也将提高

    所以我支持 room
    crclz
        11
    crclz   48 天前   ❤️ 1
    开关门的细节显然应该涉及到 Room 更多一些。如果放在 User 类,那么 Room 类就会被迫暴露更多属性,Room 类的<封装性>会被破坏。

    当然,如果加入设定“Room 类和 User 类涉及的东西一样多”,那么就应该考虑 DDD 中的 DomainService 设计。
    csfreshman
        12
    csfreshman   48 天前
    @RedisMasterNode 看面经有个帖子,不清楚是哪个部门,哈哈
    csfreshman
        13
    csfreshman   48 天前
    @winnerczwx 你这个回答后续踢人 拉人等功能,我觉得是加分项了,后面又扯到单一职责原则,非常巧妙了。
    csfreshman
        14
    csfreshman   48 天前
    @psx2019 写的没太看明白,这里怎么控制的权限,user 类里只是有个返回 roomKeys 的方法,生成这个的地方在哪?
    psx2019
        15
    psx2019   48 天前
    @csfreshman Room 对象生成的时候自动生成的,在构造函数里面,构造生成后可以获取到 key 和 roomId 用来查找和开关门,无论是谁只要持有对的 key 就可以开门,room 本身应该只关注自身状态,也就是当前门是否开启:openStatus,改变状态的动作只有一个 openOrClose(),该动作会判断 key 是否正确来决定是否改变状态,也就是持有 key 的人就是“主人”,最后实现“主人”的这一概念绑定只需要将门的 id 和 key 分别放入 User 类的 roomkeys 和 Rooms 的 Map 容器内即可实现绑定。而主人是谁其实并不是 room 关心的,只需要自己在程序上保证 key 不会别泄露给别的人即可,
    mingl0280
        16
    mingl0280   48 天前 via Android
    肯定 room 啊,怎么可能跟 user 有关联……
    Rocketer
        17
    Rocketer   48 天前 via iPhone
    按现实中的做法,应该 Room 和 User 都有东西才对。Room 有个锁,而 User 有钥匙。

    更确切地说应该是 Door 类里有个锁,这样锁就能通用了,将来踢人等其他操作也可以同样设计。

    每次验证权限的时候就 Room.Door.Unlock(User),User 有对应的钥匙就返回 true,否则返回 false,这多方便。还能授权了(把钥匙给其他 User )
    running17
        18
    running17   48 天前
    资瓷 room 类,毕竟铁打的寺庙,流水的方丈[doge]
    index90
        19
    index90   48 天前
    room 类+1,tell don't ask
    gaobing
        20
    gaobing   48 天前
    单一职责原则。开门,关门是门的功能,不同的门也可能有不同的实现。
    snw
        21
    snw   48 天前 via Android
    实现开门关门的方法当然是放在 Room 类。

    鉴权方法倒是可以考虑不同实现。
    一种是 Room 类直接记录 owner, power user id,好处是随时能显示聊天室的主人、管理员是谁,适合普通 IM 。
    另一种是上面说的 User 有个 RoomKey 钥匙串,好处是再授权不需要让 Room 知道,当然 Room 也就不知道现在谁有管理权限,适合匿名聊天。但还得做 Revoke 方法,不然万一泄漏就都成管理员了。
    UIXX
        22
    UIXX   48 天前
    LZ 问的是开门和关门的方法在 room 类里面实现还是在 user 类里面实现?

    比较浅层的答案是 room 类,因为开门和关门中的宾语“门”是 room 的一个属性。

    但深究,在允许 room 内出现一个或者多个门的情况下,则应该把“门”单独抽象成一个类(比如叫 door ),开门和关门在 door 类里面实现。更何况,根据描述,“门”必有一个“owner”的属性。

    上面很多人讨论的是权限的设计以及鉴权方式。
    chatroom 的权限设计基本上都是以“角色”为纽带来连接用户跟房间两个实体,用户具体的行为允许由角色的“策略”决定。但“角色”是安排在房间端、用户端、还是独立抽象由业务决定,很难全面地讨论。比如:
    游戏大厅这样带 lobby 的类聊天室和 QQ 群的设计可能会迥然不同,后者需要房间保留已经离线的用户信息。
    Anarchy
        23
    Anarchy   48 天前 via Android
    开关门可以理解为可进入和不可进入状态,这些都属于 room 的。如果放在 user 那边就设计为,有一类生物拥有控制房间的能力。如果开关门这个动作非常重要(比 user 本身重要)的话感觉也可以这么设计。
    newtype0092
        24
    newtype0092   48 天前
    这个问题问的比较差,正常情况只有 room 和 user 的话,不可能把对 room 的操作放在 user 里,讨论题给了二择而且是答案很明显的二择。
    问如何实现开关门操作才比较有讨论价值。
    对此场景可以从 user 派生出具有对应身份职责的子类,封装相应的职责特殊操作,或者由 user 类向 room 发出命令,根据注册房间内部的权限信息来教研。
    littlewing
        25
    littlewing   48 天前
    建议换一家公司面试
    pkupyx
        26
    pkupyx   48 天前
    room 吧,自己拥有的属性和状态变化自己维护,至于操作者和权限是另外一层含义了。而且这个动作今后未必属于 user 也是可能的。
    buhi
        27
    buhi   48 天前
    应该放在 RoomOpenSystem 里面,
    然后每个 roomEntity 有一个 LockComponent
    每个 userEntity 有一个 KeyComponent
    nekoyaki
        28
    nekoyaki   48 天前
    我觉得这问题问得就挺弱智,过于简略,问问题的人如果不愿意自己先多花点脑子设定好细节,那这种情况下当然是怎么回答都行。
    比如,如果业务逻辑偏重于描述人的能力 /权限 /行为,那么给人定义一个开门方法当然也是合理的。或者如果业务需求里有一个行为需要一个人同时开多个门的情况,那放在人身上当然也是合理的。


    另外有些回答真的是透露出一股 java 特有的化简为繁过度设计的酸臭味儿。我没特殊指代谁,别对号入座。
    zjsxwc
        29
    zjsxwc   47 天前
    “room” 可以只有 1 个“主人”, 也可以多个“主人”
    “主人” 也可以拥有 多个 “room”,

    所以

    大概率是 n 对 n 关系,使用中间对象来持有开门动作,

    小概率是 1“主人”对 n “room”关系,所以这时 “room”持有开门动作。
    zjsxwc
        30
    zjsxwc   47 天前
    很小概率 1 对 1 关系,开门动作放哪里都行。
    Blueming
        31
    Blueming   47 天前
    开门、关门,不是 User 发起的,User 只需要提供凭证(钥匙)就可以申请把 Room 的门打开,具体怎么 [打开] 应该是 Room 来。毕竟 User 并不知道,门到底是侧滑打开,卷帘门打开,还是折叠打开以及各种打开门的方式。
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2018 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 14:27 · PVG 22:27 · LAX 07:27 · JFK 10:27
    ♥ Do have faith in what you're doing.