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

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
Design patterns 沮丧可以吗?_Design Patterns_Oop_Architecture - Fatal编程技术网

Design patterns 沮丧可以吗?

Design patterns 沮丧可以吗?,design-patterns,oop,architecture,Design Patterns,Oop,Architecture,我正在设计一个用户可以扩展的框架。 基本上,我会为他们提供一组可以实现的接口,我的“manager”类会这样调用他们的实现: abstract1 = factory.GetConcreteExtension1() abstract2 = factory.GetConcreteExtension2() abstract1.DoSomething(abstract2) 我的客户机实现抽象的具体版本。 但是,他们可能会决定向不在abstract2接口中的concrete2添加数据。 这将迫使他们在c

我正在设计一个用户可以扩展的框架。 基本上,我会为他们提供一组可以实现的接口,我的“manager”类会这样调用他们的实现:

abstract1 = factory.GetConcreteExtension1()
abstract2 = factory.GetConcreteExtension2()
abstract1.DoSomething(abstract2)
我的客户机实现抽象的具体版本。 但是,他们可能会决定向不在abstract2接口中的concrete2添加数据。 这将迫使他们在concrete.DoSomething实现中将abstract2向下转换为concrete2

这看起来像是一种代码味道,因为我强制他们实现一个方法(DoSomething),该方法在其签名中期望abstract1,但实际上只能得到concrete1(另外我强制他们编写转换)


我找不到一个既能很好地定义契约又能让我的框架自己管理流程的解决方案。有什么想法吗?

这取决于你使用的语言,但在C#中,例如,您可以使用带有约束的模板来提供类型安全性,同时仍然强制类必须从抽象基类派生。

那么abstract1的DoSomething是用参数abstract2调用的,您想从DoSomething方法获取abstract2的数据吗


在这种情况下,我认为最好给出abstract2的行为,这样abstract1就可以通过abstract2的行为而不是通过它的数据与之交互。

+1。完全正确。abstract1.DoSomething(abstract2)应该调用abstract2.SomeInterfaceMethodOfAbstract2()(在concrete2中实现),而不是将abstract2向下转换到concrete2并直接访问数据。我的意思是abstract1.DoSomething(abstract2)可以调用abstract2接口中的任意数量的方法,如果它们在接口中。但是,如果所需的行为取决于abstract1和abstract2的具体类型,那么我所知道的最干净的解决方案是根据需要请求“命名”接口,如COM中的QueryInterface()。这是一个C++方法:实际上,它不是我们感兴趣的抽象行为,而是它的数据。因此abstract1需要访问concrete2.SomeData,但我不知道框架中的某些数据,因此无法将其添加到抽象api中。至于命名接口——看起来仍然像伪装中的降级…@Yaron:是的,“命名接口”是“伪装中的降级”——这只是一种以可扩展的方式管理它的方式。我们需要的是数据而不是行为:你确定你需要数据吗?假设你需要这些数据来处理X;然后,更好的方法是为abstract2提供一个接口方法,该方法返回一个abstract3类型的“command”对象,该对象包含执行X的接口方法。一个实现(例如,concrete3,它知道concrete1和concrete2的详细信息)必须实现这些方法。@Yaron:如果我建议的返回abstract3对象的附加abstract2方法确实依赖于concrete1的详细信息,那么为了使其可维护,它必须采用concrete1的“名称”,并在支持的类型表中查找它——IOW,命名的concrete类型。(查阅“多重分派”和“多重方法”。)有时,您会有成对/三元组/等交互强烈的接口类型,这种设计选择是强制的,但如果您可以设计东西,使X仅取决于具体2的细节,那么这是不必要的。但是在这种情况下,责任从被调用函数转移到调用方——它必须在泛型参数中输入正确的类型。所以它仍然是一个奇怪的api-它看起来像是泛型的,但实际上只允许一种类型…@Yaron-它是,但另一方面,这是一个有点奇怪的api开始。DoSomething()方法被声明为将“abstract2”作为参数,但它内部的逻辑可能要求它做“abstract2”不能做的事情(因此需要向下转换)。在这里我同意Hans的观点,最好的办法是确保“abstract2”类具有所有必需的行为,这样做就不必要了。然而,这是一个用户将扩展的框架。让我给你一个具体的例子:-开发人员将实现一个UI表单,该表单根据用户输入返回一些对象-由同一开发人员实现的其他对象将需要UI返回的对象作为输入。我的框架负责调用它们并向它们提供数据。这个对象将包含我在设计接口时不知道的数据。