抽象类的集合(或类似的东西......)
场景
我正在用 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)
我使用了 Daryl Teo 中描述的方法答案,但我对其进行了一些修改以包含一个枚举(因为单个汽车的数量是有限的)。因为他的答案对我最终解决方案的开发非常有帮助,所以我选择它作为最佳答案。
CarCreationStrategy 接口:
public interface CarCreationStrategy {
public void buildCar(Car car);
}
enum CarTypes implements CarCreationStrategy{
CORVETTE() {
@Override
public String toString() {
return "Corvette";
}
public void buildCar(Car car) {
car.setSpeed (0.9);
}
},
CLUNKER() {
@Override
public String toString() {
return "A piece of junk!";
}
public void buildCar(Car car) {
car.setSpeed (0.1);
}
}
}
Cars 类:
public class Cars {
private List<Car> cars = new List<Car>;
public void createCar() {
// There would be logic here to determine what kind
// We'll make a Corvette just to demonstrate
Car car = new Car(1998, CarTypes.CORVETTE);
cars.add(car);
}
}
Car 类:
public class Car {
private int year;
private double speed;
public Car(int year, CarType type) {
this.year = year;
type.buildCar(this); // Sets the speed based on CarType
}
public void setSpeed(double speed) {
this.speed = speed;
}
}
你必须在某个地方说出来——这是无法回避的。如果您有更多种类的汽车,则必须在某处指定这些属性。
我不认为子类化对您有多大帮助,除非您可以识别相似的汽车系列(例如跑车、小型货车等)。
将所有这些属性集中在一个地方的一种方法是使用工厂方法实例化 Car(它与物理汽车的制造也具有很好的对称性)。
将 Car 构造函数设为私有;有一个 CarType 枚举,它是每种类型的属性 Map 的关键;传入 CarType 并获取完全初始化的 Car。
public class Car {
private static final Map<CarType, Map<String, Object>> DEFAULT_ATTRIBUTES;
private Map<String, Object> attributes;
static {
DEFAULT_ATTRIBUTES = new HashMap<CarType, Map<String, Object>>();
// Insert values here
}
private Car(Map<String, Object> initializers) {
this.attributes = new HashMap<String, Object>(initializers);
}
public static Car create(CarType type) {
return new Car(DEFAULT_ATTRIBUTES.get(type));
}
}
我可以使用子类,也就是说,有一个由 Corvette 和 Clunker 扩展的抽象 Car 类,但是我遇到了使用 Cars 对象的问题(因为我无法收集不能的东西)不被实例化)。
这取决于您如何使用以及如何创建 Car 对象,但无论如何,创建对象应该总是很容易,我想使用工厂进行成像就可以了。
您将需要扩展您的 Car 对象以包含您通常想要的字段,并且在具体类中,您可以单独分配它们,因此您不必
Car car = new Car(1998, Corvette);
做
Car car = new Corvette(1998);
在 Corvette 类中这样
public Corvette(int year)
{
speed = 0.9;
}
:但请记住始终确保 Car 是 Corvette,克尔维特是一辆汽车。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
天哪,天哪,有很多方法可以解决这个问题,我们可以继续一整天!我会做一次大脑转储,希望这对你来说不会太难处理。
解决方案 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).