简体   繁体   English

从基类构造函数创建子类实例

[英]Creating subclass instances from base class constructor

I am learning about OOP with Java. 我正在学习使用Java的OOP。 Say I have a base class Car with subclasses that extend Car called Engine, FuelTank and Wheels. 假设我有一个基类Car,其子类扩展了Car,Engine,FuelTank和Wheels。 Is it possible to instantiate these extended classes from the base class of Car so that each instance of car will have its own instance of each subclass? 是否可以从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{}

Your question is: 你的问题是:

Inside a class, can I create instances of other classes? 在类中,我可以创建其他类的实例吗?

Well, theoretical and technical, you can easily receive the answer "yes". 那么,理论和技术,你可以很容易地得到答案“是”。 But the real answer is... "no". 但真正的答案是......“不”。 Because, if you do it: 因为,如果你这样做:

  • you are tightly coupling the class in which the instances are created ( Car ) to the classes from which the instances are created ( Engine , Wheels , FuelTank ). 在其中创建实例类(紧密耦合Car ),以从中创建实例类( EngineWheelsFuelTank )。 This way, a car will always must have a fuel tank, even though there could be implemented an electrical power only solution. 这样,即使可以实施仅电力解决方案,汽车也必须具有燃料箱。
  • the car will not only have the responsibility to go on a road, but to create its car parts by itself, too. 汽车不仅有责任走上一条路,而且还要自己制造汽车零部件。 And this is somehow... "Transformers"-like. 而这就是......“变形金刚”式的。

But, if you want to correctly learn and apply OOP, then these two situations are not a "permitted" option. 但是,如果您想正确学习和应用OOP,那么这两种情况不是“允许”选项。 It's the same as: in a normal swimming competition you could use a pair of fins, but you would be desqualified. 它与以下相同:在正常的游泳比赛中你可以使用一对鳍,但你会被取消资格。

That said, the only viable alternative to tight coupling is the loose coupling : the car parts are injected, eg passed, eg plugged into the car. 也就是说, 紧耦合的唯一可行替代方案是松耦合 :汽车零件被注入,例如通过,例如插入汽车。 In OOP, this process has the name dependency injection (DI). 在OOP中,此过程具有名称依赖注入 (DI)。 The car parts - the dependencies - can then be easily changed, or removed. 然后可以轻松更改或删除汽车零件 - 依赖项 So, the fuel tank can then be completely removed, because the car will be driven only with electrical power. 因此,可以完全移除燃料箱,因为汽车将仅通过电力驱动。 The car itself has now the single responsibility of going on a road. 汽车本身现在唯一的责任是上路。 And, even if it still depends on its parts - as it should, the car is not anymore concerned with the process of car parts creation: it just receives them - as it should. 并且,即使它仍然依赖于它的部件 - 正如它应该的那样,汽车不再关注汽车零件的制造过程:它只是接收它们 - 应该如此。

I just realised, that I'd use another conceptual scheme: an Engine should not be a CarPart . 我刚才意识到,我会使用另一种概念方案: Engine不应该是CarPart Only the fact that it's plugged into a car makes it a car part. 只有将它插入汽车才能成为汽车的一部分。 The same goes for the Wheels and FuelTank . WheelsFuelTank In short, I'd define them in other way: 简而言之,我以其他方式定义它们:

class Engine {...}
class Wheels {...}
class FuelTank {...}

class CarEngine extends Engine {...}
class CarWheels extends Wheels {...}
class CarFuelTank extends FuelTank {...}

So, the loose coupling will be applied like this: 因此,松散耦合将如下应用:

class Car{

    Car(instance of CarEngine, instance of CarWheels, instance of CarFuelTank){
        //...
    }

}

or, even better, in analogy with your code version: 或者,更好的是,与您的代码版本类似:

class Car {

    Car(instance of Engine, instance of Wheels, instance of FuelTank){
        //...
    }

}

Here are two wonderful resources for a better understanding of the principles presented here: 以下是两个很好的资源,可以更好地理解这里提出的原则:

Good luck with your projects! 祝你的项目好运!


EDIT 1: 编辑1:

@Ryan The Leach kindly and rightly proposed me to also present you the notion/concept of factory . @Ryan The Leach善意并且正确地建议我也向您介绍工厂的概念/概念。 I'll try to do it in a principle manner. 我会尝试以原则的方式做到这一点。

The car needs an engine to be able to function. 汽车需要一台发动机才能发挥作用。 But who could produce this car part? 但谁可以生产这种汽车零件? Well: an engine factory. 嗯:发动机工厂。 More precisely a car engine factory. 更确切地说是汽车发动机工厂。

In terms of OOP, a factory is a specialized class having a single responsibility: the creation of instances of other classes (sounds familiar?). 就OOP而言, 工厂是一个具有单一责任的专业类: 创建其他类的实例 (听起来很熟悉?)。 The created instances are then used somewhere else, according with their usefulness. 然后根据其实用性在其他地方使用创建的实例。 Now, when a factory creates an object, or more objects of different class types, it may need to gather/produce other resources too, in order to prepare the creation of the final "product(s)". 现在,当工厂创建一个对象或更多不同类类型的对象时,它可能也需要收集/生成其他资源,以便准备创建最终的“产品”。

So, an engine factory would first need to gather/produce a lot of engine pieces before assembling/creating the final engine. 因此,在组装/创建最终发动机之前,发动机工厂首先需要收集/生产大量发动机零件。 The same applies to a car factory: it needs to receive an engine from the engine factory, wheels from the wheels factory and a fuel tank from the fuel tanks factory. 这同样适用于汽车制造厂:它需要从发动机工厂接收发动机,从车轮工厂接收车轮,从燃料箱工厂接收燃料箱。 Then it produces the final cars. 然后它生产最终的汽车。

In OOP, there are three types of factories, eg of so called factory patterns : 在OOP中,有三种类型的工厂,例如所谓的工厂模式

  • The simple factory 简单的工厂
  • The factory method and 工厂方法
  • The abstract factory . 抽象工厂

I'll not present them here personally, but I'll try to direct you to some (very) good web resources, easy to follow and understand: 我不会在这里亲自介绍它们,但我会尝试引导您访问一些(非常)良好的Web资源,易于理解和遵循:

PS: PS:

The first two are my favorites... although I didn't watched them yet :-) Yes, silly, isn't it? 前两个是我最喜欢的......虽然我还没看过它们:-)是的,傻,不是吗? Because they are relative new uploads I didn't knew that they exist. 因为它们是相对较新的上传,所以我不知道它们存在。 BUT: I followed all the other streams of the author and, in three words: I was impressed. 但是:我跟随了作者的所有其他流,用三个词:我印象深刻。 Nota bene: the author explains all the patterns presented in the book " Head First Design Patterns ". Nota bene:作者解释了“ Head First Design Patterns书中提出的所有模式

From Syntax point of view , yes you can declare and create the instances of child class in Parent base class as below. 从语法的角度来看,是的,您可以在Parent基类中声明和创建子类的实例,如下所示。

public class Base {
     public void someMethod(){
         Child child1 = new Child(); // valid
         Base child2 = new Child(); // valid
    }
}

public class Child extends Base{

}

Good Practices and OOPs design point of view : You should not create objects of child class in base class. 良好实践和OOP设计观点:您不应在基类中创建子类的对象。

You should inherit a class B from A only when B behaves like A with some additional behaviors. 只有当B 行为A有一些额外的行为时,才应该从A继承B类。

Usually it happens the Base class is written befor the child sub classes. 通常会发生Base类是为子子类编写的。 While writing the Base Class you can not know in future which classes and how many classes are going to extend it. 在编写基类时,您将来无法知道哪些类和多少类将扩展它。 You should practice not modifying the existing class (its called Open closed principle). 您应该练习不修改现有类(称为Open closed principle)。 Of course requirements gets refined, redefined and result in refactoring the classes or design. 当然,需求得到改进,重新定义并导致重构​​类或设计。 Its a principle, a guideline, you need not follow it too strictly but always keep it in mind and when ever you voilate it you must have a very good reason to do so. 它是一个原则,一个指导方针,你不需要太严格地遵循它,但始终牢记它,当你发出它时,你必须有一个很好的理由这样做。 Inheritence itself is not a very good prqctice as it exposes a internals of parent class to the child class. 继承本身并不是一个非常好的prqctice,因为它将父类的内部暴露给子类。 Its often called as white box reuse. 它通常被称为白盒重用。 It breaks encapsulation in a way. 它以某种方式打破了封装。 For this purpose you should favor composition over inheritence . 为此,你应该赞成composition不是inheritence

In your case your Car class should have instance reference fields for the object of Wheel , Engine etc. 在您的情况下,您的Car类应具有WheelEngine等对象的实例引用字段。

If you want to add more flexibility to your code you can go one step ahead and define interfaces for Wheel , Engine and then have your class Car depend only upon these interfaces. 如果您想为代码添加更多灵活性,您可以向前迈出一步,为WheelEngine定义接口,然后让您的类Car仅依赖于这些接口。 This will protect you in case tomorrow you decide to add new variety of Wheel (like NormalWheel , AlloyWheel) or you decide to create the car instance with inhanced different implementation of engine, then these classes can just confirm to the defined interfaces and the concrete objects of the required Engine or Wheel can be injected in Car class. 这将保护您,以防明天您决定添加新种类的Wheel (如NormalWheel,AlloyWheel)或您决定使用增强的不同实现的引擎创建汽车实例,然后这些类可以确认到已定义的接口和具体对象可以在Car class中注入所需的发动机或车轮。 Depending upon interfaces rather than concrete class protects you from modification of already tested and stable code later. 取决于接口而不是具体类,可以保护您不再修改已经过测试过的稳定代码。

Let's consider your Car example. 让我们考虑你的汽车例子。

Base class should be a general form of what you select as the class.It should not be specific. 基类应该是您选择作为类的一般形式。它不应该是特定的。

Extended class or Sub class should be a specific version base class. 扩展类或Sub类应该是特定的版本基类。 If Car is your base class, then your sub classes should be SportCar , Taxi , RacingCar etc. 如果Car是你的基类,那么你的子类应该是SportCarTaxiRacingCar等。

For example, SportCar is a specific version of Car which has more features which are specific to it's task. 例如, SportCarCar的特定版本,具有更多特定于其任务的功能。

There should be a Is-A Relationship between sub class and base class. 子类和基类之间应该存在Is-A关系

"Sub class" is a "Base calss" . “Sub class”是“Base calss”

Hope this will be helpful...... 希望这会有所帮助......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM