简体   繁体   中英

Creating subclass instances from base class constructor

I am learning about OOP with Java. Say I have a base class Car with subclasses that extend Car called Engine, FuelTank and 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?

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 ). 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. 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). 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 . Only the fact that it's plugged into a car makes it a car part. The same goes for the Wheels and FuelTank . 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:

@Ryan The Leach kindly and rightly proposed me to also present you the notion/concept of factory . 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?). 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 :

  • 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:

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 ".

From Syntax point of view , yes you can declare and create the instances of child class in Parent base class as below.

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.

You should inherit a class B from A only when B behaves like A with some additional behaviors.

Usually it happens the Base class is written befor the child sub classes. 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). 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. Its often called as white box reuse. It breaks encapsulation in a way. For this purpose you should favor composition over inheritence .

In your case your Car class should have instance reference fields for the object of Wheel , Engine etc.

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. 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. 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. If Car is your base class, then your sub classes should be SportCar , Taxi , RacingCar etc.

For example, SportCar is a specific version of Car which has more features which are specific to it's task.

There should be a Is-A Relationship between sub class and base class.

"Sub class" is a "Base calss" .

Hope this will be helpful......

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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