Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop ';是';界面设计不好_Oop_Design Patterns - Fatal编程技术网

Oop ';是';界面设计不好

Oop ';是';界面设计不好,oop,design-patterns,Oop,Design Patterns,假设我有一个a级 class A { Z source; } 现在,上下文告诉我,“Z”可以是不同类(比如B和C)的实例,它们在继承树中不共享任何公共类 我想最简单的方法是让“Z”成为一个接口类,然后让类B和C实现它 但有些东西仍然不能说服我,因为每次使用类A的实例时,我都需要知道“源”的类型。所以,在多个“如果”中,所有的结尾都是instanceof,这听起来不太好。也许将来会有其他类实现Z,而这种类型的硬编码“ifs”肯定会破坏某些东西 问题的关键在于,我无法通过向Z添加函数来解决问

假设我有一个a级

class A
{
   Z source;
}
现在,上下文告诉我,“Z”可以是不同类(比如B和C)的实例,它们在继承树中不共享任何公共类

我想最简单的方法是让“Z”成为一个接口类,然后让类B和C实现它

但有些东西仍然不能说服我,因为每次使用类A的实例时,我都需要知道“源”的类型。所以,在多个“如果”中,所有的结尾都是instanceof,这听起来不太好。也许将来会有其他类实现Z,而这种类型的硬编码“ifs”肯定会破坏某些东西

问题的关键在于,我无法通过向Z添加函数来解决问题,因为在Z的每个实例类型中所做的工作都是不同的

我希望有人能给我一些建议,也许是一些有用的设计模式

谢谢

编辑:“某人”在获取某个实例时在某个地方所做的工作完全不同于接口Z后面的类。这就是问题所在,完成“重要工作”的实体不是Z,而是想知道谁是Z的其他人

编辑2:也许一个具体的例子会有帮助:

class Picture
{
  Artist a;
}

interface Artist
{
}

class Human : Artist { }

class Robot : Artist {}
现在我在某处有一个
图片的实例

Picture p = getPicture();
// Now is the moment that depending if the type of `p.a` different jobs are done
// it doesn't matter any data or logic inside Human or Robot

使用接口的目的是隐藏这些不同的实现<代码>一个应该只知道方法的意图或高级目的

Z
的每个实现所做的工作可能不同,但用于调用该工作的方法签名可以相同。类
A
可以只调用方法
Z.foo()
,并且根据Z的实现是
B
还是
C
,将执行不同的代码

您唯一需要知道实际实现类型的时候是需要对两种不同类型执行完全不相关的处理,并且它们不共享接口。但在这种情况下,为什么它们由同一个A类处理?现在,在某些情况下,这可能是有意义的,例如
B
C
是从XML模式生成的类,您不能修改它们,但通常这表明设计可以改进

更新了,现在您已经添加了图片示例。我想这证实了我的观点——尽管
getPicture()
的实现不同,但目的和返回类型是相同的。在这两种情况下,艺术家都会返回一张图片

如果调用方希望以相同的方式处理机器人创建的图片和人类创建的图片,那么他们将使用艺术家界面。他们不需要区分人和机器人,因为他们只需要一张照片!如何创建图片的详细信息属于子类,调用者不应该看到这些详细信息。如果调用者关心图片是如何创建的,那么调用者应该绘制图片,而不是绘制机器人或人类,并且设计会完全不同

如果您的子类正在执行完全不相关的任务(这不是您的Artist示例所显示的!),那么您可能会使用非常模糊的接口,例如标准Java;在这种情况下,调用方实际上不知道
run()
方法将做什么-它只知道如何运行
Runnable
的东西

链接

下面的问题/文章提出了
instanceof
的一些替代方案:

下面的文章也给出了示例代码,使用了一个与您类似的示例:

下面的文章讨论了
instanceof
与其他方法(如访问者模式和非循环访问者)之间的权衡:


我认为你需要发布更多信息,因为我现在看到的是对OOP原则的误解。如果您使用的是一种通用接口类型,那么根据Liskov替换原则,源的类型应该无关紧要。

我将把您的a、B和C类称为Alpha、Beta和Gamma

也许Alpha可以分为两个版本,一个使用Beta,另一个使用Gamma。这将避免Alpha中的
instanceof
检查,正如您所猜测的,这确实是一种代码味道

abstract class Alpha
{
    abstract void useSource();
}

class BetaAlpha extends Alpha
{
    Beta source;
    void useSource() { source.doSomeBetaThing(); }
}

class GammaAlpha extends Alpha
{
    Gamma source;
    void useSource() { source.doSomeGammaThing(); }
}
事实上,这是非常普遍的。考虑流类的一个更具体的例子,它可以使用文件或套接字。在本例中,文件和套接字不是从任何公共基类派生的。事实上,它们甚至可能不在我们的控制之下,所以我们无法改变它们

abstract class Stream
{
    abstract void open();
    abstract void close();
}

class FileStream extends Stream
{
    File file;
    void open()  { file.open();  }
    void close() { file.close(); }
}

class SocketStream extends Stream
{
    Socket socket;
    void open()  { socket.connect();    }
    void close() { socket.disconnect(); }
}

你能解释一下为什么你真的需要知道Z的真正类型吗?只要你知道它的接口(可用的方法等),你就可以做你需要的一切。我添加了一些额外的信息。@DanielMonteiro:在很多情况下,一个人会有一个对象集合,其中一些继承或实现
Foo
,而另一些则没有,我们希望对集合中的所有对象执行一个可以为所有对象定义的操作,但是通过
Foo
的实例可以更好地执行该操作。在这种情况下使用
instanceof
在我看来是完全合适的。@DanielMonteiro:这不仅仅是为了接口;如果访问另一个对象的内部可以实现任何其他方式都无法实现的加速,则它也适用。例如,
列表
的实现可能提供一个接受
列表
的构造函数;如果传入的对象以实现知道的格式存储其数据,则构造函数可以比必须通过接口执行所有操作时更快地复制数据。可以肯定的是,这表明Java需要(但没有)一种标准方法……一个数组支持的类型可以公开一个数组进行临时只读访问(比如