例如:
class Vehicle {
Collection<Axle> axles;
}
class Axle {
Collection<Wheel> wheels;
}
class Wheel {
// I think there are dually rims that take two tires -- just go with it
Collection<Tire> tires;
}
class Tire {
int width;
int diameter;
}
我有一项服务,通过该服务我可以获得我所知道的所有车辆对象的集合。现在说我有一个特定宽度和直径的轮胎,我想找一辆可以拿它的车。简单的方法是有一组四个嵌套循环,如下所示:
for (Vehicle vehicle : vehicles) {
for (Axle axle : vehicle.getAxles()) {
for (Wheel wheel : axle.getWheels()) {
for (Tire tire : wheel.getTires()) {
if (tire.width == targetWidth
&& tire.diameter == targetDiameter) {
// do something
break;
}
}
}
}
}
这有一个好的设计模式吗?还是要使用更好的数据结构?将一个指数保留在轮胎信息映射到车辆的位置会不会更好?
修改:回答评论中的问题
您是否可以控制从服务中收到的数据结构?
是
您是否需要在同一数据中多次搜索不同的轮胎?
是
性能是一个问题吗?
不是特别
当你找到轮胎时,你只需要知道哪辆车载有它还是你还需要车轴和车轮?
有时只是车辆,有时只是车轴 - 两种不同的背景
您是否需要参考找到的轮胎?
是的,在我需要轴的情况下
EDIT2 : 进一步扩展隐喻,解释上述两种情况:
背景1 - 我想知道车辆,所以我可以派一名工人来收集车辆并将其带回来
背景2 - 我想知道轴和轮胎,因为我正在尝试做这项工作的车辆
答案 0 :(得分:2)
您可以使用Java 8 streams来展平循环。
vehicles.stream()
.flatMap(vehicle -> vehicle.getAxles().stream())
.flatMap(axle -> axle.getWheels().stream())
.flatMap(wheel -> wheel.getTires().stream())
.filter(tire -> tire.width == targetWidth
&& tire.diameter == targetDiameter)
.forEach(tire -> {
// do something
});
关于流的好处是,您可以在序列中的任何位置轻松插入其他filter
,filter
,findAny
等等。
答案 1 :(得分:2)
我会改变你的逻辑并将问题移到Vehicle
,除非你因为任何其他原因而想要保持你的物体变薄(在这种情况下我会亲自用较厚的物体包裹它们)添加所需的任何行为)
class Vehicle {
...
public Tire acceptsTire(Tire tire) {
}
}
从这里开始,有几种可能性,具体取决于这个业务逻辑在您的域中的重要性。
Tire
集合,也可以是TireSpecification
1}}构造Vehicle
时的实例如果由于任何原因你需要保持这些分开(你的意图在问题上不是很明确,是汽车上的轮胎还是只是适合的规格?)< / LI>
醇>
答案 2 :(得分:1)
如果不改变您的数据结构,您将无法发挥重大作用。你可以用lambdas添加一些语法糖,但它基本上是相同的解决方案。
你可以看到的东西:
Vehicles
零轴或百轴。虽然这取决于您的商业模式,但似乎很奇怪。Axle
,Wheel
),它们只包含内部对象的集合。如果它们只是具有getAllInnerTypes()
的简单JavaBean对象,那么您应该考虑删除此类。甚至可能是轮胎信息应该几乎直接存储在Vehicle
类中。答案 3 :(得分:0)
只要没有太多的项目和/或性能不是一个大问题,我可能会选择嵌套循环(或来自John的回答)。
由于您有两个搜索上下文,您可以将相应的操作传递给搜索方法 - 类似这样(在这种情况下使用循环):
interface TireAction {
void doSomething(Vehicle v, Axle a, Tire t);
}
void findTireAndPerform(int targetWidth, int targetDiameter, TireAction action) {
for (Vehicle vehicle : vehicles) {
for (Axle axle : vehicle.getAxles()) {
for (Wheel wheel : axle.getWheels()) {
for (Tire tire : wheel.getTires()) {
if (tire.width == targetWidth && tire.diameter == targetDiameter) {
action.doSomething(vehicle, axle, tire);
break;
}
}
}
}
}
}
void someMethod() {
...
findTireAndPerform(width, diameter, (v, a, t) -> {
// send worker to 'v'
});
...
findTireAndPerform(width, diameter, (v, a, t) -> {
// work on 'a' and 't'
});
}