如何解决表示派生类的“容器”是从基类的容器派生的一种设计模式
我有一个Track
类,其中包含一组Point
,并且可以及时表示人的位置。为了获得此结果,我运行了一个迭代优化例程,该例程组合了不同的数据。为了做到这一点,我用类Point
扩展了OptimizedPoint
,该类保存用于此点和当前值的优化数据。我还介绍了OptimizedTrack,它是OptimizedPoints
的集合,以及与整个轨道相关的优化所需的其他数据。
我在OptimizedTrack
上进行了优化,在最后一次迭代中,我返回到用户纯数据(Track
),该数据仅具有结果而没有其他数据。但是,我找不到一种用OOP表示OptimizedTrack
是Track
的扩展并为其引入通用例程的方法。 F.e获得了一段对他们两个都应该可用的轨道的长度,因为它只使用在OptimizedTrack
和Track
中都可以找到的数据
现在我拥有这样的体系结构Point{x,y,z},OptimizedPoint extends Point {additional_data}. Track {array<Point>},OptimizedTrack {array<OptimizedPoint>,additional_data}
。我无法理解如何表达OptimizedTrack
是Track的扩展,因为我无法表达array<OptimizedPoint>
扩展array<Point>
。因此,我无法介绍可以为数组计算的通用例程length
,因此也可以从数组计算得出。
我不坚持当前的体系结构。这很可能是错误的,我只在这里写下来表达我所面临的问题。在这种情况下,您打算如何重构我的体系结构?
解决方法
我相信,如果您遵循被认为正确使用继承来表达子类型关系的方法,那么您尝试做的基本前提就是错误的。
继承可以用于各种目的,我不希望对这个问题有所怀疑,但是大多数权威人士认为,继承用于子类型化时最好且最安全地使用。简而言之,子类的实例应该能够代替其基类的实例而不会“破坏”程序(请参阅:Liskov替代原理)。
让我们假设OptimizedPoint
是Point
的子类型。然后,在类Point
上实例上调用的类OptimizedPoint
中定义的所有方法将继续按预期运行。这意味着OptimizedPoint
不能在这些方法调用中要求任何更严格的前提条件,也不能削弱合同Point
所制定的任何允许的后置条件。
但这是一个普遍的谬论,因为OptimizedPoint
是Point
的子类型,而OptimizedPoint
的容器(即OptimizedTrack
)是Point
的容器的子类型Track
,即OptimizedTrack
。这是因为您无法将Track
的实例替换为Point
的实例(因为您无法将OptimizedTrack
的实例添加到OptimizedTrack
的实例中)
因此,如果您尝试遵循“良好的面向对象设计原则”,那么尝试以某种方式使Track
成为Track
的子类是灾难性的,因为它肯定永远不会成为一个子类型。当然,您可以重用OptimizedTrack
以使用合成来构建OptimizedTrack
,即Track
将包含在length
的实例中,诸如String quote = "To be or not to be that is the question";
System.out.println(medianWordLength(quote));
static double medianWordLength(String words) {
String[] parts = words.split("\\s+");
double median = 0;
// sort the array based on length of the words
Arrays.sort(parts,(a,b) -> Integer.compare(a.length(),b.length()));
for (String v : parts) {
System.out.println(v);
}
System.out.println("------------------");
// get the "middle" index.
int idx = parts.length / 2;
// adjust index based on array size
if (parts.length % 2 == 0) {
System.out.println(parts[idx-1] + " " + parts[idx]);
median = (parts[idx-1].length() + parts[idx].length())
/ 2.;
} else {
System.out.println(parts[idx]);
median = parts[idx + 1].length();
}
return median;
}
之类的方法将被委派。
考虑到Track
本身就是OptimizedTrack
,我不确定为什么要在优化过程之后将Track
返回到客户代码。以下是我认为您要实现的目标的简要示例(用Kotlin编写,因为不太冗长)。
如果您认为Track
是Point
类型的点的可迭代对象,则可以实现更大的灵活性并解决类型问题。这样,当您从OptTrack
扩展Track
时,您将能够:
- 可以毫无问题地替换
Track
和OptTrack
(即使您优化的跟踪对象尚未计算出简化的Track
对象)。 - 简化
optimize
并从Track
返回OptTrack
,没有问题(optimize
上的Point
函数是不相关的,您可以返回{{ 1}}在您的OptPoint
内,因为它扩展了对象Track
)
Point
,
在OOP中,您应该更喜欢对象组合而不是对象继承。对于您的问题,我认为创建指向和跟踪的界面可能会有所帮助。为了获得适当的结果,我认为,您应该创建两个接口,即IPoint和ITrack。 Track和OptimizedTrack都实现ITrack接口,并且对于常见操作,您可以创建另一个类,两个类都将请求委托给它。之后,您可以创建一个策略类,使用ITrack并返回另一个优化的ITrack。在ITrack中,您可以创建GetPath,该GetPath返回IPoint类型的对象的列表。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。