简体   繁体   中英

Constructor Chaining with subclasses in Java

Just a question RE: Constructor Chaining in subclasses that I can't find a good answer on and I'm confusing myself a bit with.

I'm making a basic little Text Based RPG for some practice and I'm going through my constructors for an abstract class and have the constructors from 0-4 params chained together like below

abstract class Creature { 

// Fields
private String name;
private int lifeForce;
private int strength;
private int agility;

// Constructors + Chaining
public Creature() { 
    this("Unknown")
}
public Creature(String name) { 
    this(name, 100);
}
public Creature(String name, int lifeForce)  {
    this(name, lifeForce, 10);
}
public Creature(String name, int lifeForce, int strength) {
    this(name, lifeForce, strength, 10);
}

public Creature(String name, int lifeForce, int strength, int agility) {
    this.name = name;
    this.lifeForce = lifeForce;
    this.strength = strength;
    this.agility = agility;
}

My confusion is how best to format the constructors of a subclass of creature, for example this simple Person class introduces two new fields. There's definitely too much repetition if I write the constructors like this

// Constructors + Chaining
public Person() { 
    super("Unknown");
    this.skillClass=new Mage();
    this.dialogue="...";

}

public Person(String name) { 
    super(name);
    this.skillClass=new Mage();
    this.dialogue="...";
    
} etc etc etc 

I suppose I could restrict the constructors to limit the repetition but I'm mostly just wondering if there's good best practice that I'm missing here.

Any and all suggestions welcome and if anyone has any good resources to recommend that go deeper than the usual

Class B extends Class A

examples I'd massively appreciate.

In situations like this one when you need to use multiple constructors with different parameters, it is recommended to use the builder pattern like this :

abstract class Creature { 

// Fields
private String name;
private int lifeForce;
private int strength;
private int agility;

private Creature(Builder<?> builder) {
    this.name = builder.name;
    this.lifeForce = builder.lifeForce;
    // Add the other attributes here.
}

public static abstract Builder extends Builder<T extends Builder<T>> {
    private String name;
    private int lifeForce;
    private int strength;
    private int agility;

    public Builder(//here you put the attributes that you need to have in all instances) {
            // here you do the affectations.
       }
       // now you need to make the functions that set each property :
       public Builder lifeForce(int lifeForce) {
              this.lifeForce = lifeForce;
              return this;
       }
       // you do the same thing for all the other attributes.
       ...
       public Creature build() {
              return new Creature(this);
       }
 }
}

So for the explanation : This pattern will allow you to create instances of your class by setting only the needed attributes.

As here you have subclasses the builder pattern will be little bit more harder to understand but it is the perfect solution in such situation.

We need to apply the builder pattern also for every subclasse so let's do it for the person class :

public class Person extends Creature {
       private int anotherField;
       public Person(Builder builder) {
              super(builder);
              this.anotherField = anotherField;
       }
       public static Builder extends Creature.Builder<Builder> {
              public Builder(//add the fieldHere if it is needed in all class instances) {
              // if the field is not mandatory you can omit this constructor but you need to put the function below.
       }
       public Builder anotherField(int anotherField) {
              this.anotherField = anotherField;
       }
       public Person build() {
              return new Person(this);
       }
}

Now let me show you how tricky is this solution :

1/ declare person with 2 fields :

Person p1 = Person.Builder().name("name").anotherField(0).build();

2/ declare another one with just one field

Person p2 = Person.Builder().agility(1000).build();

Remark : In these two examples, i supposed that your builders' constructors don't have parameters. If for example the name is mandatory field :

Person p3 = Person.Builder("name").anotherField(0).build();

I wish that you had the idea about using builder pattern.

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