oop - 方法需要特定的子类型,但集合是基本抽象类型。怎么了?
问题描述
最近我陷入了这样的境地。我正在概括这个问题,因为我认为它更多地与结构设计有关,而不是具体问题。
一般问题
有一个类的层次结构:一个抽象基类和一些Base
继承自它的实体。该类包含一个对象的类型集合。需要来自某个服务类的计算,但方法只接受 type 的集合。假设这很重要,因为如果输入集合包含任何其他类型,则返回的值就是错误的。D1
D2
D3
A
Base
A
B
B.process()
D1
A
有一个接口,允许客户端将元素添加到内部集合,它不会以任何其他方式公开。可以为相同的客户端构造层次结构中的类并将新值传递给A
;A
没有足够的上下文来自己构建它们。
尝试、问题和想法
我主要关心的是需要在运行时确定A
集合中每个元素的类型,因此可以过滤正确的元素并传递给B.process()
. 即使它是可能的(这是我的特殊问题,稍后会更多)它似乎是错误的!我认为包含对抽象基类的引用的对象不必知道它拥有的具体实例。
我试着:
- 将参数类型更改为
B.process(c: Base[])
soA
不必向下转换类型,但它不能解决任何问题:A
仍然需要过滤元素,否则计算会出错。 - 将完整的集合传递
Base[]
给B.process()
但只是将选择/向下转换的问题推迟到B
. - 放入一个
process()
方法Base
可以D1
覆盖行为(众所周知的多态性)。这里的问题是process()
返回一个SomeValue
类型对D1
. - 分离添加元素的接口,以便更具体的
A.addD1Element(e: D1)
方法可以允许将D1
对象放在不同的集合中并将其传递给B
. 它应该可以工作,但看起来......不知道,很奇怪。如果基于参数类型的方法重载是可能的,那么至少该过程对于类的客户来说不会那么麻烦。 - 只需将
D1
层次结构的类分开即可。这是前一个更激进的变体。问题是这D1
似乎与整个层次结构有关,除了B
.
这些是我对这个问题的一些想法。
例如,所使用的语言支持在运行时检查对象的类型(instanceof
),并且很容易根据该检查过滤集合。但正如我所说,我的问题与范式更相关。一种语言怎么样,比如 C++,在哪里做这样的检查不太方便?
那么有什么办法可以解决这类问题呢?可以应用什么样的重构或设计模式,以便问题易于处理或简单地消失?
这个问题看起来很相关,但我相信这是更笼统的(尽管我提供了更具体的上下文)。最受欢迎的答案建议分成不同的集合。这也是我正在考虑的一个想法,但是A
每次添加新类型时都会强制更改实现。
上下文(实际问题)
我问的是笼统的方式,因为它确实让我很感兴趣,但我知道大多数时候设计只能在它试图解决的特定问题的背景下进行分析。
手头的问题与此类似:
A
是一个类(某种实体,如 DDD 实体),它对客户为服务产生的某种协议或债务进行建模。它有不同的费用,包括月薪。Base
和相关的类是不同类型的付款。它们有很多共同点,尽管大部分都是数据(日期、金额、兴趣等);但至少有一种付款类型具有不同的附加信息:每月付款 ( D1
)。需要仔细分析这些付款,以便B
使用更多上下文信息和该类型的所有付款一次负责不同的类 ( )。该服务需要特定于这些付款的附加数据,因此无法接收摘要Payment
类型(至少不是那种设计)。其他支付没有具体信息MonthlyPayment
,因此它们无法生成业务需要和B
正在生成的价值(在其他支付类型中没有意义)。
所有付款都存储在同一个集合中,因此该类的其他方法可以以通用方式处理所有付款。
这主要是上下文。我认为设计不是最好的,但我看不到更好的设计。
如前所述,也许只在不同的集合中分离MonthlyPayment
( ) ?D1
但这不是唯一需要额外处理的付款(虽然它是最复杂的),所以我可以为每种付款类型提供不同的收款,并且根本没有层次结构。目前有四种支付类型,其中两种需要额外的具体分析,但以后可以添加更多类型,并且每次添加新类型时都需要修改实现的问题仍然存在。
这是按类型对不同集合进行更离散的方法,这里是更好的方法吗?抽象基类Payment
仍可用于可通过公共接口操作的支付。我也可以使用layer 超类型或类似的东西来允许重新利用公共功能(该语言也允许一种混合)并停止使用基类作为层次结构的根。
超频。我很抱歉文本的长度。我希望它至少是可读和清晰的。非常感谢您提前。
解决方案
推荐阅读
- amazon-redshift - Redshift 物化视图不刷新或删除
- macos - MacOS 从 PDF 渲染图像(没有第三方渲染库)
- c# - 统一保存某个时刻的浮点值
- typescript - 从抽象类扩展的类中的抽象方法的键入问题
- c++ - 为什么 WSARecv 在 gRPC 中出现 WSAEFAULT 错误?
- javascript - 如何在 NestJS 中正确注入提供程序?
- apache-spark - Spark中的广播变量null
- c - 当结构非常简单时,malloc 是结构与整个结构的“成员”
- javascript - 在 JavaScript 中重用测试输入的最佳实践
- reactjs - 当 URL 中的路径没有将您带到想要的组件时该怎么办?