我正在学习使用Java的OOP。假设我有一个基类Car,其子类扩展了Car,Engine,FuelTank和Wheels。是否可以从Car的基类中实例化这些扩展类,以便每个car实例都有自己的每个子类的实例?
class Car{
Car(){
// instance of Engine
// instance of Wheels
// instance of FuelTank
}
}
class CarPart{}
class Engine extends CarPart{}
class Wheels extends CarPart{}
class FuelTank extends CarPart{}
答案 0 :(得分:4)
你的问题是:
在课程中,我可以创建其他课程的实例吗?
那么,理论和技术上,你可以很容易地得到答案“是”。但真正的答案是......“不”。因为,如果你这样做:
Car
)与创建实例的类紧密耦合({{1} },Engine
,Wheels
)。这样,即使可以实施仅电力解决方案,汽车也必须始终有燃料箱。但是,如果您想正确学习和应用OOP,那么这两种情况不是“允许”选项。它与以下相同:在正常的游泳比赛中,你可以使用一对鳍,但你会被取消资格。
也就是说,紧耦合的唯一可行替代方案是松散耦合:汽车零件被注入,例如:通过,例如插上车。在OOP中,此过程的名称为依赖注入(DI)。然后可以轻松更改或删除汽车零件 - 依赖关系。因此,可以完全移除燃料箱,因为汽车将仅通过电力驱动。汽车本身现在唯一的责任是上路。并且,即使它仍然依赖于它的部件 - 正如它应该的那样,汽车不再关注汽车零件的制造过程:它只是接收它们 - 应该如此。
我刚才意识到,我会使用另一个概念方案:FuelTank
不应该是Engine
。只有将它插入汽车才能成为汽车的一部分。 CarPart
和Wheels
也是如此。简而言之,我会以其他方式定义它们:
FuelTank
因此,松散耦合将如下所示:
class Engine {...}
class Wheels {...}
class FuelTank {...}
class CarEngine extends Engine {...}
class CarWheels extends Wheels {...}
class CarFuelTank extends FuelTank {...}
或者,甚至更好,与您的代码版本类似:
class Car{
Car(instance of CarEngine, instance of CarWheels, instance of CarFuelTank){
//...
}
}
以下是两个很好的资源,可以更好地理解这里提出的原则:
祝你的项目好运!
@Ryan Leach善意并且正确地建议我也向您介绍工厂的概念/概念。我会尝试以原则的方式做到这一点。
汽车需要一台发动机才能运转。但谁可以生产这种汽车零件?嗯:发动机工厂。更准确地说是一家汽车发动机工厂。
就OOP而言,工厂是一个专门的职责,只有一个责任:创建其他类的实例(听起来很熟悉?)。然后根据其实用性在其他地方使用创建的实例。现在,当工厂创建一个对象或更多不同类类型的对象时,它可能也需要收集/生成其他资源,以便准备创建最终的“产品”。
因此,在组装/创建最终发动机之前,发动机工厂首先需要收集/生产大量发动机零件。这同样适用于汽车制造厂:它需要从发动机工厂接收发动机,从车轮工厂接收车轮,从燃料箱工厂接收燃料箱。然后它生产出最终的汽车。
在OOP中,有三种类型的工厂,例如所谓的工厂模式:
我不会在这里亲自介绍他们,但我会尝试引导您访问一些(非常)良好的网络资源,易于理解和遵循:
P.S:
前两个是我最喜欢的......虽然我还没有看过它们:-)是的,傻,不是吗?因为它们是相对较新的上传,所以我不知道它们存在。但是:我跟随了作者的所有其他流,用三个词:我印象深刻。 Nota bene:作者解释了“ Head First Design Patterns ”一书中提出的所有模式。
答案 1 :(得分:2)
从语法的角度来看,是的,您可以在Parent基类中声明和创建子类的实例,如下所示。
public class Base {
public void someMethod(){
Child child1 = new Child(); // valid
Base child2 = new Child(); // valid
}
}
public class Child extends Base{
}
良好实践和OOP设计观点:您不应在基类中创建子类的对象。
只有在B
行为(如A
时)以及其他一些行为时,才应从B
继承课程A
。
通常会发生Base类是为子子类编写的。在编写基类时,您将来无法知道哪些类和多少类将扩展它。您应该练习不修改现有类(称为Open closed principle)。当然,需求得到改进,重新定义并导致重构类或设计。它是一个原则,一个指导方针,你不需要过于严格地遵循它,但始终牢记它,当你想要它时,你必须有一个非常好的理由这样做。
继承本身并不是一个非常好的prqctice,因为它将父类的内部暴露给子类。它通常被称为白盒重用。它以某种方式打破了封装。为此,您应该composition
优先于inheritence
。
在您的情况下,您的Car
类应包含Wheel
,Engine
等对象的实例引用字段。
如果您想为代码添加更多灵活性,您可以提前一步,为Wheel
,Engine
定义接口,然后让您的类Car
仅依赖于这些接口。这将保护您,以防明天您决定添加新的Wheel
(如NormalWheel,AlloyWheel)或您决定使用增强的不同引擎实现创建汽车实例,然后这些类可以确认到定义的接口所需的引擎或车轮的具体对象可以在Car
类中注入。取决于接口而不是具体类,可以保护您不再修改已经过测试过的稳定代码。
答案 2 :(得分:0)
让我们考虑你的 Car 示例。
基类应该是您选择作为类的一般形式。它不应该是特定的。
扩展类或Sub类应该是特定的版本基类。如果Car是您的基类,那么您的子类应该是 SportCar , Taxi , RacingCar 等。
例如, SportCar 是 Car 的特定版本,其具有更多特定于其任务的功能。
子类和基类之间应该存在 Is-A Relationship 。
" Sub class"是一个" Base calss" 。
希望这会有所帮助......