抽象类的集合(或类似的东西......)
场景
我正在用 Java 编写一个涉及汽车的程序。
注意:我(尽我所能)简化了这个场景,使其更通用、更容易理解。我实际上并没有使用汽车。
我创建了一个 Cars
类,它是 Car
对象的集合。
Car
对象有一个speed
(双精度)和一个year
(int)。构造函数将年份作为参数,例如:
public class Car {
private int year;
private double speed;
public Car(int year) {
this.year = year;
}
}
这是棘手的部分...汽车必须有一种类型(比如说 Corvette 或 Clunker)。 Corvette 的速度
为0.9
,Clunker 的速度
为0.1
。如果不指定Car
应该是什么类型的汽车,就永远无法实例化它。现在,为了创建一辆汽车,我们需要:
Car car = new Car(1998, Corvette);
我们刚刚创建的 Corvette 将是一个 Car
对象,speed
为 0.9
。
问题
我的实际情况涉及到更多种类的汽车,每种汽车除了速度
之外还有几个特定的属性(也许还有颜色
的字段) 、numDoors
和 fuelTankSize
)。由于汽车种类繁多(每种汽车都有自己的特定属性),代码变得比我想象的更加复杂。
可能的解决方案
我可以使用子类,即有一个由
Corvette
和Crunker 扩展的抽象
,但后来我遇到了使用Car
类Cars
对象的问题(因为我无法创建无法实例化的东西的集合)。 请参阅下面的编辑。使用枚举(例如
CarKind
)似乎需要几个混乱的 switch 语句:- 填充每辆车的
速度
字段 - 从
Cars
类创建Car
对象 - 等等
- 填充每辆车的
如何提供帮助
我正在寻找一种解决方案,允许单个 Cars
类包含每个 <代码>汽车对象。我不想要不同的收藏(例如Corvettes
、Clunkers
)。我还在寻找一种解决方案,允许根据单个汽车类型的属性创建 Car
对象...如前所述,创建一个新的 Car
Corvette
的速度
为0.9
。不应该有其他方法来指定汽车的速度
。
在这种情况下有最佳实践吗?我举的例子够清楚了吗?
谢谢。
编辑:我不想要抽象 Car
对象的集合的原因是因为 Cars
集合的目的是创建和操作 Car
对象,无论其种类如何。 Car
是抽象的,似乎使这个问题变得复杂。如果您认为这是最好的解决方案,请相应地回答。
The Scenario
I'm making a program in Java that involves cars.
NOTE: I've simplified this scenario (to the best of my ability) to make it both more general and easier to understand. I'm not actually working with cars.
I've created a Cars
class, which is a collection of Car
objects.
The Car
object has a speed
(double) and a year
(int). The constructor takes the year as a parameter, for example:
public class Car {
private int year;
private double speed;
public Car(int year) {
this.year = year;
}
}
Here's the tricky part... A car must have a kind (let's say Corvette or Clunker). A Corvette will have a speed
of 0.9
and a Clunker will have a speed
of 0.1
. A Car
can never be instantiated without specifying what kind of car it should be. So now, to create a car, we have:
Car car = new Car(1998, Corvette);
The Corvette we've just created will be a Car
object with a speed
of 0.9
.
The Problem
My actual situation involves many more kinds of cars, and each car has several specific attributes besides speed
(maybe there are also fields for color
, numDoors
and fuelTankSize
). With so many kinds of cars (each with their own specific attributes), the code is becoming more complex than I'd like.
Possible Solutions
I could work with sub classes, that is, have an abstract
Car
class that's extended byCorvette
andClunker
, but then I have the problem of using aCars
object (because I can't make a collection of something that can't be instantiated). See EDIT below.Using an enum (such as
CarKind
) seemingly requires several messy switch statements:- to populate the
speed
field of each car - to create
Car
objects from theCars
class - etc.
- to populate the
How You Can Help
I'm looking for a solution that allows a single Cars
class to contain every Car
object. I don't want different collections (like Corvettes
, Clunkers
). I'm also looking for a solution that allows the creation of Car
objects based on the attributes of an individual car kind... as previously mentioned, creating a new Car
of kind Corvette
would result in a speed
of 0.9
. There should be no other way to specify a car's speed
.
Is there a best practice in this situation? Have I made the example clear enough?
Thanks.
EDIT: The reason I don't want a collection of abstract Car
objects is because the point of the Cars
collection is to create and manipulate Car
objects, regardless of their kinds. Car
being abstract seems to complicate this. If you think this is the best solution, please answer accordingly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
天哪,天哪,有很多方法可以解决这个问题,我们可以继续一整天!我会做一次大脑转储,希望这对你来说不会太难处理。
解决方案 1:使用策略。
策略基本上是一种将大量可替换逻辑与另一个类分开的方法。在这种情况下,每辆车都需要进行不同的设计。对此,有一个策略是完美的。
抱歉,如果我不小心混入了一些 C#...自从我使用 java 以来已经很长时间了。
现在,您可以向汽车构造函数传递策略。
所以,你现在得到的东西真是太棒了!
这将完全满足您的要求。
然而,你会得到策略和汽车之间的耦合。
解决方案 2:使用 Factory。
Factory 也是一个不错的解决方案,而且可能更简单。您要做的就是拥有一个 CarFactory,其中具有用于创建每种类型汽车的多个工厂方法。
用法:
所以这样做的好处是您现在不必担心实例化 Car。它全部由 CarFactory 处理,将您的“实例化逻辑”与代码解耦。但是,您仍然需要知道要构建哪辆车并相应地调用该方法,这仍然是一个小的耦合。
解决方案 3:策略工厂!
因此,如果我们想摆脱最后一点耦合,让我们将两者结合在一起!
现在你有了一个制造汽车的策略,一个为你制造汽车的工厂,以及一辆没有你原来的额外接头的汽车。太棒了,不是吗?
如果您使用过 Swing,您会注意到这就是它们处理诸如布局之类的一些事情的方式(GridBagLayout、GridLayout 都是策略)。还有一个 BorderFactory。
改进
抽象策略
使用此功能,您可以灵活地动态创建 AbstractStrategies(例如,从数据存储中提取汽车属性)。
Oh boy oh boy there are so many ways to deal with this that we could go on all day! I will do a brain dump, and hopefully it will not be too much for you to deal with.
solution 1: use Strategy.
A strategy is basically a way to separate heavy substitutable logic from another class. In this case, every car needs to be created differently. A strategy is PERFECT for this.
Sorry if I mix in some C# by accident... been a long time since I javaed.
Now, you can pass a strategy in with your car constructor.
So, what you get now is so awesome!
And this will do exactly what you want.
However, you get a coupling between the strategy and the Car.
solution 2: use Factory.
Factory is an okay solution for this as well, and is probably easier. What you do is have a CarFactory, with multiple factory methods for creating each type of car.
Usage:
So the good thing about this is you don't have to worry about instantiating Car now. its all handled by CarFactory, decoupling your "instantiation logic" from your code. However, you still need to know which car you want to build and call that method accordingly, which is still a small coupling.
solution 3: strategy factory!
So, if we wanted to get rid of that last bit of couplings, lets combine the two together!
Now you have a Strategy for building cars, a Factory that builds them for you, and a Car with no extra couplings from your original. Wonderful, isn't it?
If you have worked with Swing, you will notice that this is how they handle a few things like the Layouts (GridBagLayout, GridLayout are all strategies). There's also a BorderFactory as well.
Improvement
Abstract Strategy
Using this gives you the flexibility to create AbstractStrategies on the fly (say, pulling car properties from a data store).
我使用了 Daryl Teo 中描述的方法答案,但我对其进行了一些修改以包含一个枚举(因为单个汽车的数量是有限的)。因为他的答案对我最终解决方案的开发非常有帮助,所以我选择它作为最佳答案。
CarCreationStrategy 接口:
Cars 类:
Car 类:
I used the method described in Daryl Teo's answer, but I modified it a little bit to include an enum (since there are a finite number of individual cars). Because his answer was so instrumental to the development of my final solution, I selected it as the best answer.
The CarCreationStrategy interface:
The Cars class:
The Car class:
你必须在某个地方说出来——这是无法回避的。如果您有更多种类的汽车,则必须在某处指定这些属性。
我不认为子类化对您有多大帮助,除非您可以识别相似的汽车系列(例如跑车、小型货车等)。
将所有这些属性集中在一个地方的一种方法是使用工厂方法实例化 Car(它与物理汽车的制造也具有很好的对称性)。
将 Car 构造函数设为私有;有一个 CarType 枚举,它是每种类型的属性 Map 的关键;传入 CarType 并获取完全初始化的 Car。
You have to say it someplace - there's no getting around that. If you have many more kinds of Cars, you'll have to specify those attributes somewhere.
I don't see where subclassing helps you much, unless you can identify families of cars that are similar (e.g. sports cars, mini-vans, etc.).
One way to centralize all those attributes in one place is to instantiate Car using a factory method (it has a nice symmetry with manufacturing of physical cars, too).
Make the Car constructor private; have an enumeration of CarType that is the key into a Map of attributes for each type; pass in the CarType and get back a Car, fully initialized.
这取决于您如何使用以及如何创建 Car 对象,但无论如何,创建对象应该总是很容易,我想使用工厂进行成像就可以了。
您将需要扩展您的 Car 对象以包含您通常想要的字段,并且在具体类中,您可以单独分配它们,因此您不必
做
在 Corvette 类中这样
:但请记住始终确保 Car 是 Corvette,克尔维特是一辆汽车。
It depends on how you use and how you create your Car object, but anyway, creating your object should always been easy, I'd imaging using a factory will do.
You will need to extend your Car object to have fields you wanted in general, and in concrete class, you can assign them individually, so instead of
you do
and in your Corvette class:
But keep in mind always make sure Car is a Corvette, and Corvette is a Car.