Zhiroslav
Zhiroslav

Reputation: 51

Instantiate an extended class or its parent (depending on circumstances)

Let's say I have a class named Human in ProjectA. It is instantiated in the CreatureBuilder class of the same project.

Now I want to create a new class called Cyborg in a different project, i.e. in ProjectB. ProjectB has ProjectA in its imports, but ProjectA knows nothing about ProjectB.

Cyborg extends Human, and must also be instantiated by CreatureBuilder of ProjectA (so, Cyborg is located in ProjectB, I call CreatureBuilder from ProjectB to instantiate Cyborg, but CreatureBuilder is located in ProjectA, as well as my Human class).

I need a logic to create a Human when CreatureBuilder is instantiated from ProjectA, and to create a Cyborg when CreatureBuilder is instantiated from ProjectB.

I think it is achievable by creating an interface with a getCreature() method in ProjectA. This method will be overridden in ProjectB to return new Cyborg and then passed back to CreatureBuilder of ProjectA. Any other suggestions? What do you think is the best workaround? Can I use reflection API instead?

Cheers!

Upvotes: 3

Views: 240

Answers (2)

Spotted
Spotted

Reputation: 4091

Java 8

CreatureBuilder can delegate the creature's creation to the caller by asking for a Supplier.

public class CreatureBuilder {
    public Creature getCreature(Supplier<Creature> creatureSupplier)
    {
        //do some unknown things
        return creatureSupplier.get();
    }
}

Usage from ProjectA

public class ProjectA {
    public static void main(String[] args) {
        Creature A = new CreatureBuilder().getCreature(Human::new);
    }
}

Usage from ProjectB

public class ProjectB {
    public static void main(String[] args) {
        Creature B = new CreatureBuilder().getCreature(Cyborg::new);
    }
}

And never use reflection if you're not forced to.

Java 7

If you're sticked with Java 7, the principle remains the same except that it's a bit more verbose.

You have to declare and use your own Supplier-like interface

public interface CreatureSupplier {
    Creature get();
}

public class CreatureBuilder {
    public Creature getCreature(CreatureSupplier creatureSupplier)
    {
        //do some things
        return creatureSupplier.get();
    }
}

Usage is a bit more verbose

public class ProjectA {
    public static void main(String[] args) {
        Creature A = new CreatureBuilder().getCreature(new CreatureSupplier() {
            @Override
            public Creature get() {
                return new Human();
            }
        });
    }
}

public class ProjectB {
    public static void main(String[] args) {
        Creature B = new CreatureBuilder().getCreature(new CreatureSupplier() {
            @Override
            public Creature get() {
                return new Cyborg();
            }
        });
    }
}

And... that's it, you've got the same behaviour as the one in Java 8.

Upvotes: 5

SomeDude
SomeDude

Reputation: 14228

I think you are looking at factory pattern. Yes you can do it with an interface and a factory class in project A and a factory class in B that extends it.

Example:

In Project A:

public interface CreatureBuilder
{
   Creature getCreature(String type);
}

public class Creature
{
   //fields of Creature class
}

public class Human extends Creature
{
  //fields of Human
}

public class Ape extends Creature
{
  //fields of Ape
}



public class ProjectAFactory implements CreatureBuilder
{
   @Override
   public Creature getCreature( String type )
   {
      switch(type)
      {
         case("Human"): return new Human();
         case("Ape") : return new Ape();
         default : return null;
      }
   }
}

You can call ProjectAFactory.getCreature("Human"); to create Human object

Then in project B

public class ProjectBFactory extends ProjectAFactory
{
    @Override
    public Creature getCreature(String type)
    {
       switch(type)
       {
          case ( "Cyborg" ) : return new Cyborg();
          default : return super.getCreature(type);
       }
    }

}


public class Cyborg extends Creature
{
   //fields related to Cyborg which also fields of Creature in project A
}

You can call ProjectBFactory.getCreature("Cyborg"); to create Cyborg or even ProjectBFactory.getCreature("Human") to get a Human Object.

Upvotes: 1

Related Questions