抽象类的集合(或类似的东西...) [英] A Collection of an Abstract Class (or something like that...)
问题描述
场景
我正在制作一个涉及汽车的Java程序。
注意:我已经简化了这个场景(尽我所能),使它更一般和更容易理解。我实际上不是在与汽车工作。
我创建了一个 Cars
是 Car
对象的集合。
Car
对象具有速度
(双)和年
(int)。构造函数以年为参数,例如:
public class Car {
private int year;
私人双倍速度;
public Car(int year){
this.year = year;
}
}
这里是棘手的部分...一种(我们说科尔维特或克隆)。 Corvette将有速度
的 0.9
,Clunker将有速度
of 0.1
。 A Car
永远不能实例化,而不指定应该是什么样的汽车。现在,创建一辆汽车,我们有:
Car car = new Car(1998,Corvette);
我们刚刚创建的Corvette将是 Car
对象与速度
的 0.9
。
问题
我的实际情况涉及更多种类的汽车,除了速度
(也许还有 color
, numDoors
和 fuelTankSize
)。有了这么多种汽车(每种都有自己的特定属性),代码变得比我想要的更复杂。
可能的解决方案
-
我可以使用子类,也就是说,有一个抽象
Car
类扩展Corvette
和Clunker
,但是我有使用Cars
对象(因为我不能创建一个不能被实例化的东西的集合)。 -
使用枚举(例如
CarKind
)似乎需要几个乱码开关语句:
- 填充每个车辆的
速度
- 从
汽车
班 $创建 - 等。
汽车
b $ b
- 填充每个车辆的
我正在寻找一个解决方案,允许单个 Cars
类包含每个 Car
对象。我不想要不同的集合(例如 Corvettes
, Clunkers
)。我也在寻找一个解决方案,允许创建 Car
对象基于个人汽车的属性...如前所述,创建一个新的汽车
种类 Corvette
会导致速度
的 0.9
。没有其他方法可以指定汽车的速度
。
在这种情况下有最佳做法吗?
编辑:我不想要的原因集合的抽象 Car
对象是因为 Cars
集合的点是创建和操作 Car
对象,无论它们的种类。 汽车
是抽象的似乎使这复杂化。
我在寻找一个解决方案,允许单个Cars类包含
每个Car对象。我不想要不同的集合(如Corvettes,
Clunkers)。我也在寻找一个解决方案,允许创建
基于个人汽车的属性的汽车对象...如前所述的
,创建一个新的汽车科尔维特会导致
在0.9的速度。没有其他方法可以指定汽车的
速度。
哦男孩哦,男孩有这么多种方式处理这一点,我们可以一整天!我会做一个大脑转储,希望它不会太多,你可以处理。
解决方案1:使用策略。
策略基本上是一种将重复的可替换逻辑与另一个类分离的方法。在这种情况下,每个汽车都需要不同的创建。一个策略是完美的。
对不起,如果我偶然混合一些C#...自从javaed以来很长时间了。
public interface CarCreationStrategy {
void BuildCar(Car theCar);
}
public class CorvetteStrategy implements CarCreationStrategy {
public void BuildCar(Car theCar){
theCar.Type =Corvette;
theCar.Speed = 0.9;
theCar.Comments =Speedster!;
}
}
public class ToyotaStrategy implements CarCreationStrategy {
public void BuildCar(Car theCar){
theCar.Type =Toyota;
theCar.Speed =0.5;
theCar.Comments =永远不会死,即使你从建筑物的顶部掉落;
}
}
现在,
public class Car {
//变量...
public Car (CarCreationStrategy策略,int年){
strategy.BuildCar(this); //在这里实现您的属性。
this.year = year;
}
}
所以,你现在得到的是如此真棒! / p>
列表< Car> cars = new List< Car>();
cars.Add(new Car(new CorvetteStrategy(),1999));
cars.Add(new Car(new ToyotaStrategy(),2011);
解决方案2:使用工厂。
工厂是一个很好的解决方案,你可以更容易,你做的是有一个CarFactory,有多种工厂方法创建每种类型的汽车。
public class CarFactory {
public static Car BuildCorvette(int year){
Car car = new Car(year);
car.Type =Corvette;
car.Speed = 0.9;
return car;
}
public static Car BuildToyota(int year){
Car car = new Car(year);
car.Type = Toyota;
car.Speed = 0.5;
return car;
}
}
用法:
列表< Car> cars = new List< Car>
cars.Add(CarFactory.BuildCorvette(1999));
cars.Add(CarFactory.BuildToyota(2011));
所以关于这一点的好处是你不必担心实例化Car现在。它的所有由CarFactory处理,解耦你的实例化逻辑从你的代码。但是,你仍然需要知道你要建立哪辆车,并相应地调用该方法,这仍然是一个小联系。
解决方案3:策略工厂!
所以,如果我们想摆脱最后一点的耦合, !
public class CarFactory {
public static Car BuildCar(CarCreationStrategy strategy,int year){
Car car = new Car(year);
strategy.BuildCar(car);
return car;
}
}
List< Car> cars = new List< Car>();
cars.Add(CarFactory.BuildCar(new CorvetteStrategy(),1999));
cars.Add(CarFactory.BuildCar(new ToyotaStrategy(),2011);
你有一个建立汽车的战略,一个工厂,为你建立他们,一辆汽车没有从你的原来的额外的联轴器。很好,不是吗?
如果你已经使用了Swing,你会注意到这是他们如何处理像Layouts(GridBagLayout,GridLayout都是策略)等一些东西。还有一个BorderFactory。
< hr>
改进
抽象策略
code> public interface CarCreationStrategy {
void BuildCar(Car theCar);
}
public class AbstractStrategy:CarCreationStrategy {
public string Type;
public double Speed;
public string注释;
public void BuildCar(Car theCar){
theCar.Type = this.Type;
Car.Speed = this .Speed;
theCar.Comments = this.Comments;
}
}
public class CorvetteStrategy extends AbstractStrategy {
public CorvetteStrategy(){
this.Type =Corvette;
this.Speed = 0.9;
this.Comments =Speedster!;
}
}
public class ToyotaStrategy extends AbstractStrategy {
public ToyotaStrategy {
this.Type =Toyota;
this.Speed =0.5;
this.Comments =永远不会死,即使你从建筑物的顶部掉落;
}
}
使用它可以灵活地创建AbstractStrategies (例如,从数据存储中提取汽车属性)。
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.
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.
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.
public interface CarCreationStrategy{
void BuildCar(Car theCar);
}
public class CorvetteStrategy implements CarCreationStrategy{
public void BuildCar(Car theCar){
theCar.Type = "Corvette";
theCar.Speed = 0.9;
theCar.Comments = "Speedster!";
}
}
public class ToyotaStrategy implements CarCreationStrategy{
public void BuildCar(Car theCar){
theCar.Type = "Toyota";
theCar.Speed = "0.5";
theCar.Comments = "Never dies, even if you drop it from the top of a building";
}
}
Now, you can pass a strategy in with your car constructor.
public class Car{
// Variables ...
public Car(CarCreationStrategy strategy, int year){
strategy.BuildCar(this); // Implements your properties here.
this.year = year;
}
}
So, what you get now is so awesome!
List<Car> cars = new List<Car>();
cars.Add(new Car(new CorvetteStrategy(),1999));
cars.Add(new Car(new ToyotaStrategy(),2011);
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.
public class CarFactory{
public static Car BuildCorvette(int year){
Car car = new Car(year);
car.Type = "Corvette;
car.Speed = 0.9";
return car;
}
public static Car BuildToyota(int year){
Car car = new Car(year);
car.Type = "Toyota;
car.Speed = 0.5";
return car;
}
}
Usage:
List<Car> cars = new List<Car>();
cars.Add(CarFactory.BuildCorvette(1999));
cars.Add(CarFactory.BuildToyota(2011));
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!
public class CarFactory{
public static Car BuildCar(CarCreationStrategy strategy, int year){
Car car = new Car(year);
strategy.BuildCar(car);
return car;
}
}
List<Car> cars = new List<Car>();
cars.Add(CarFactory.BuildCar(new CorvetteStrategy(),1999));
cars.Add(CarFactory.BuildCar(new ToyotaStrategy(),2011);
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
public interface CarCreationStrategy{
void BuildCar(Car theCar);
}
public class AbstractStrategy:CarCreationStrategy{
public string Type;
public double Speed;
public string Comments;
public void BuildCar(Car theCar){
theCar.Type = this.Type;
theCar.Speed = this.Speed;
theCar.Comments = this.Comments;
}
}
public class CorvetteStrategy extends AbstractStrategy{
public CorvetteStrategy(){
this.Type = "Corvette";
this.Speed = 0.9;
this.Comments = "Speedster!";
}
}
public class ToyotaStrategy extends AbstractStrategy{
public ToyotaStrategy{
this.Type = "Toyota";
this.Speed = "0.5";
this.Comments = "Never dies, even if you drop it from the top of a building";
}
}
Using this gives you the flexibility to create AbstractStrategies on the fly (say, pulling car properties from a data store).
这篇关于抽象类的集合(或类似的东西...)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!