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

面试题讨论,类设计

  •  
  •   csfreshman · 2021-04-24 17:35:04 +08:00 · 3328 次点击
    这是一个创建于 393 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

    要我就按照最复杂的来搞

    请个保安
    nuistzhou
        7
    nuistzhou  
       2021-04-24 19:44:23 +08:00 via iPhone
    很简单吧,就是类的设计吧。我也选开关门的 method 放在 room 里,user 可以有个 type 为字典的属性,开关门的 method 验证该用户的这个字典里是否有这个 room 的 key,来鉴权。
    charlie21
        8
    charlie21  
       2021-04-24 19:50:39 +08:00
    左手右手一个慢动作 右手左手慢动作重播
    先写一个 room interface 这是它需要的
    psx2019
        9
    psx2019  
       2021-04-24 21:48:49 +08:00
    ```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  
       2021-04-24 22:11:15 +08:00   ❤️ 1
    同菜鸡

    猜测一下面试官想考啥吧

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

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

    所以我支持 room
    crclz
        11
    crclz  
       2021-04-24 22:30:31 +08:00   ❤️ 1
    开关门的细节显然应该涉及到 Room 更多一些。如果放在 User 类,那么 Room 类就会被迫暴露更多属性,Room 类的<封装性>会被破坏。

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

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

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

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

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

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

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


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

    所以

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

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