Vveeb
V2EX  ›  问与答

[.Net] 新手求问一个关于 类、接口设计,实例化的问题

  •  
  •   Vveeb · Mar 11, 2021 · 1829 views
    This topic created in 2062 days ago, the information mentioned may be changed or developed.

    由于实际业务描述起来更麻烦点,所以我就举个栗子吧。

    我有一个机器人类Robot 然后这个机器人可以扫地DoClean(),所以要给它一把笤帚UsedTool.

    然后我就定义了一个笤帚ITool的接口,只要继承并实现了接口里方法的类,就可以给Robot用来扫地,到此为止,应该是可以应对大多数情况了,应该算是一个比较正常的逻辑了,是吧?

    然后我就遇到了一个问题,出现了一个新型笤帚SuperCleanTool,它虽然勉强实现了ITool接口,但是现在的Robot.DoClean() 是达不到效果的(可能是笤帚太重了挥不动?这样的意外情况)。

    所以我就想,是不是要搞一个Robot的子类——RobotPro : Robot,在这个子类里重写一下DoClean()方法,这样的话,如果给我一把这个新型笤帚,我就new RobotPro();让它去扫地。

    但是!我该怎么让调用 /实例化 Robot的类知道什么时候该实例化出一个Robot什么时候该实例化出一个RobotPro呢?

    本来是想先判断一下ITool 对象是不是SuperCleanTool的:

    if(UsedTool is SuperCleanTool tool)
    {
        new RobotPro()
        {
            UsedTool = tool;
        }
    }
    

    但是显然是不行的,因为我的Robot & ITool都是在一个项目里的,而SuperCleanTool 是在另外的项目里,所以SuperCleanTool要实现ITool接口就要先添加Robot所在项目的引用,要在Robot的代码里这样判断,是没办法回过头去引用SuperCleanTool项目的(反正我是在 VS 里添加项目引用的时候提示出错了)

    所以来问问大佬们,怎么实现根据不同需求,创建不同类型的实例,或者说,还能改成什么样的设计?

    Supplement 1  ·  Mar 11, 2021

    @cxe2v

    Robot 应该只是持有 ITool 这个接口,然后包含 DoClean()方法,方法里使用 ITool 的具体实例

    是的,目前的设计就是这么个情况。

    现在出现了 SuperCleanTool,但它显然不会继承你定义的 ITool 接口

    是的,因为接口是先定义好的,后来出现的SuperCleanTool,但是它的实际情况有点超出了预期,为了能把它套用到先前的设计,感觉就好像是插不上的接口要硬插。策略模式和工厂模式倒是听说过,看来我是需要去仔细研究研究了哈哈。

    @jtwor 感谢老哥亲自敲代码回复,你说的“因为有点不理解为什么 Robot 继承 ITool ”, Robot并没有继承ITool啦。 是Robot和ITool放在了一起(一个命名空间?下?)啦。就比方说叫——“家政机器人军团” RobotArmy。所以说考虑到机器人打扫房间要用到工具,就定义了工具接口。

    看了您定义的 ITool接口,里面有string UsedTool() 这个方法,但是我现在面临的问题就是,先前定义接口里没有定义这个方法,为的就是不想每次继承都实现一遍这个方法。然后看了你的回复也让我理了理思路。

    可能笤帚不是个很好的例子,我来给它换成_多功能吸尘器_的Tool吧。

    这样的话,我的ITool里就有: 开机、吸尘、洒水、拖地

    然后我的Robot.DoClean()方法里就可以顺序地写上 开机,吸尘,洒水,拖地,然后大功告成。

    但是我在实现SuperCleanTool : ITool 的时候,发现这是个“带水箱自动拖地吸尘器”,它没办法真正地实现“洒水”这个方法,所以我相当于是在实现洒水的时候,写了个空的。而在最后一步“拖地”的时候, 进行了“洒水”+“拖地”。

    所以就带来了问题,这个SuperCleanTool单独用的话,是能用的,但是交给我的机器人用,他就不会了,因为他在使用这个工具的时候,洒水,水并没有被洒出来,他就不知道水撒了多了还是少了,进而不知道下一步拖地该怎么去做了(是拖一下就给水擦干了,还是拖三下才能给水擦干?因为他不知道水洒出来多少)

    7 replies  •  2021-03-11 23:57:38 +08:00
    geelaw
    geelaw
    Mar 11, 2021 via iPhone
    1
    尝试改变例子可能会起到反作用。

    如果工具知道自己应该被谁使用,那么 ITool 可以有一个 CreateToolUser 方法。
    hahastudio
    hahastudio
    Mar 11, 2021
    2
    > 如果给我一把这个新型笤帚,我就 new RobotPro();让它去扫地。
    在我看来,问题出在这里,你需要 ITool 加一个接口让调用它的地方知道它的型号

    比如 ITool 里添加一个接口,叫 GetModel(),返回型号;或者叫 GetWeight(),返回重量
    这样的话,也不太需要 RobotPro
    jtwor
    jtwor
    Mar 11, 2021
    3
    有点乱。。。是笤帚 决定 Robot 是 pro 或者 normal 还是 Robot 的类型决定使用 pro 或者 normal 的笤帚

    下面是根据传入的笤帚 返回不同的 clean 效果
    有些 interface 的改动。。因为有点不理解为什么 Robot 继承 ITool 机器是机器 工具是工具
    /* */
    public class Robot : IRobot {
    private ITool _tool { get; set; }

    public Robot(ITool tool) {
    _tool = tool;
    }

    public void DoClean() {
    Console.WriteLine(_tool.UsedTool());
    }

    }

    public class SuperTool:ITool {
    public string _status = "太重了挥不动";
    public string UsedTool() { return _status; }
    }

    public class NormalTool:ITool {
    public string _status = "开始扫地";
    public string UsedTool() { return _status; }
    }

    public interface ITool {
    string UsedTool();
    }

    public interface IRobot {
    void DoClean();
    }



    ITool super = new SuperTool();
    ITool normal = new NormalTool();

    Robot robot = new Robot(normal);//装备普通工具
    robot.DoClean();//开始扫地
    robot = new Robot(super);//装备超级工具
    robot.DoClean();//太重了挥不动

    /* */
    jtwor
    jtwor
    Mar 11, 2021
    4
    其实感觉就是在问依赖反转的问题
    cxe2v
    cxe2v
    Mar 11, 2021
    5
    你这个架构就有点问题

    Robot 应该只是持有 ITool 这个接口,然后包含 DoClean()方法,方法里使用 ITool 的具体实例,
    现在出现了 SuperCleanTool,但它显然不会继承你定义的 ITool 接口,所以这里你无法用持有的 ITool 这个接口去接住 SuperCleanTool,你只能新定义一个属性去接收,然后定义一个新的 DoCleanWithSuperCleanTool 方法去使用这个 SuperCleanTool,再然后,你只能在 Robot 外部去判定该给 Robot 的那个 Tool 属性赋值了

    这个需求的话,简单的你可以参考策略模式,复杂的,你可以参考工厂模式
    Vveeb
    Vveeb
    OP
    Mar 11, 2021
    6
    @jtwor 接了条帖子好像没有 艾特上你
    forgottencoast
    forgottencoast
    Mar 11, 2021
    7
    @Vveeb 我建议你写一个简化的项目放在 GitHub 上,不然这样很难说清楚。
    有了代码,大家一看就明白了。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1427 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 22:30 · PVG 06:30 · LAX 14:30 · JFK 17:30
    ♥ Do have faith in what you're doing.