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

2021-03-11 17:37:18 +08:00
 Vveeb

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

我有一个机器人类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 里添加项目引用的时候提示出错了)

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

1083 次点击
所在节点    问与答
7 条回复
geelaw
2021-03-11 17:43:09 +08:00
尝试改变例子可能会起到反作用。

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

比如 ITool 里添加一个接口,叫 GetModel(),返回型号;或者叫 GetWeight(),返回重量
这样的话,也不太需要 RobotPro
jtwor
2021-03-11 18:33:34 +08:00
有点乱。。。是笤帚 决定 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
2021-03-11 18:35:07 +08:00
其实感觉就是在问依赖反转的问题
cxe2v
2021-03-11 18:45:14 +08:00
你这个架构就有点问题

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

这个需求的话,简单的你可以参考策略模式,复杂的,你可以参考工厂模式
Vveeb
2021-03-11 20:25:36 +08:00
@jtwor 接了条帖子好像没有 艾特上你
forgottencoast
2021-03-11 23:57:38 +08:00
@Vveeb 我建议你写一个简化的项目放在 GitHub 上,不然这样很难说清楚。
有了代码,大家一看就明白了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/760765

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX