1
\$\begingroup\$

I have a class MassiveDTO that contains lists. At some point in the project, I need to generate an object of this class, that will contain some hardcoded data. I would like to know if there is a better way (or a design pattern) to populate those lists with known data.

With the method generateLists I populate them and I use them later on. Keep in mind, I need this class not to be static because I reuse it on the project.

MassiveDTO class

public class MassiveDTO {

  private List<String> company = new ArrayList<>();
  private List<String> partners = new ArrayList<>();
  private List<String> biodata = new ArrayList<>();

  public MassiveDTO(){}

  public MassiveDTO(List<String> company, List<String> partners, List<String> biodata) {
    super();
    this.company = company ;
    this.partners = partners ;
    this.biodata = biodata;
  }


  /** Getters and Setters **/
  public List<String> getCompany() {
    return company;
  }

  public void setCompany(List<String> company) {
    this.company = company;
  }

  public List<String> getPartners() {
    return partners;
  }

  public void setPartners(List<String> partners) {
    this.partners = partners;
  }

  public List<String> getBiodata() {
    return biodata;
  }

  public void setBiodata(List<String> biodata) {
    this.biodata = biodata;
  }

  public void generateLists(){
    /** Company**/
    company.add("X0788");
    company.add("X0192");


    /** Partners **/
    partners.add("X0081");

    /** Biodata**/
    biodata.add("X0913");

  }

}

My first idea is to create another static class that will extend MassiveDTO in order to reuse those lists, and that class will be static because I will only need it to contain those specific lists with their data.

\$\endgroup\$
  • 2
    \$\begingroup\$ Greetings, you should use data files for this, not code. This way you dont have recompile every time the static data changes. If you dont want this question closed, you should add the getters and setters, because otherwise this is not-working (or at least pointless) code. \$\endgroup\$ – konijn Nov 5 at 12:48
  • \$\begingroup\$ @konijn You are absolutly correct, I just added them \$\endgroup\$ – valkongr Nov 5 at 12:51
  • \$\begingroup\$ What do you mean with "reuse it on the project"? It does not sound like something that would normally prevents fields from being static. \$\endgroup\$ – TorbenPutkonen Nov 5 at 13:28
  • \$\begingroup\$ @TorbenPutkonen this class is being used as a request body for example \$\endgroup\$ – valkongr Nov 5 at 13:44
  • \$\begingroup\$ What's the class really being used for? MassiveDTO obviously isn't a good name. It's really hard to suggest alternatives without the real scenario. What if there's an entirely different, better approach to the overall problem? \$\endgroup\$ – dustytrash Nov 6 at 1:25
2
\$\begingroup\$

So you need to separate the construction of that class from the class itself? This is the Factory Pattern.

Data class

Boil down to your DTO to ... well the data.

public class MassiveDTO {
    private final List<String> company;
    private final List<String> partners;
    private final List<String> biodata;

  /**
   * @see MassiveDTOBuilder
   */
  MassiveDTO(List<String> company, List<String> partners, List<String> biodata) {
    this.company = company;
    this.partners = partners;
    this.biodata = biodata;
  }
   ... getters only
}

Factory Pattern

Then have a second class, MassiveDTOFactory, that calls that constructor with suitable fixed values.

public class MassiveDTOFactory {
  public static MassiveDTO create() {
    return new MassiveDTO(
      List.of("X0788", "X0192"), // Here we use Java 9 immutable collections
      List.of("X0081"),
      List.of("X0913")
    );
  }
}

Fluent Builder Pattern

If you wish more flexibility on the values then a Fluent Builder is for you. Something like this:

public class MassiveDTOBuilder {
  private List<String> companies = new ArrayList<>();
  private List<String> partners = new ArrayList<>();
  private List<String> biodata = new ArrayList<>();

  public static MassiveDTOBuilder massiveDto() {
    return new MassiveDTOBuilder();
  }

  private MassiveDTOBuilder() {
  }

  public MassiveDTOBuilder withCompany(String... items) {
    for (String i : items) {
      companies.add(i);
    }
    return this;
  }

  public MassiveDTOBuilder withPartner(String... items) {
    for (String i : items) {
      partners.add(i);
    }
    return this;
  }

  public MassiveDTOBuilder withBiodata(String... items) {
    for (String i : items) {
      biodata.add(i);
    }
    return this;
  }

  public MassiveDTO build() {
    return new MassiveDTO(
      Collections.unmodifiableList(companies),
      Collections.unmodifiableList(partners),
      Collections.unmodifiableList(biodata)
    );
  }
}

Which can used like:

MassiveDTO m = massiveDto()
  .withCompany("X0788", "X0192")
  .withPartner("X0081")
  .withBiodata("X0913")
  .build();
\$\endgroup\$
  • \$\begingroup\$ A lot of useful information, thanks very much. \$\endgroup\$ – valkongr Nov 13 at 9:07
1
\$\begingroup\$

OK, so what I understand, class MassiveDTO will be instantiated sometimes in your application, but those 3 lists can be static and won't change. So solution is create classes with static hard coded lists (3 classes) and just use static reference them in MassiveDTO:

public class MassiveDTO {

private List<String> company = CompanyDataHolder.COMPANY_LIST;
private List<String> partners = PartnersDataHolder.PARTNERS_LIST;
private List<String> biodata = BiodataHolder.BIODATA_LIST;

// you probably dont even need setters
public List<String> getCompany() {
    return company == null ? Collections.emptyList() : company;
}

public void setCompany(List<String> company) {
    this.company = company;
}

public List<String> getPartners() {
    return partners == null ? Collections.emptyList() : partners;
}

public void setPartners(List<String> partners) {
    this.partners = partners;
}

public List<String> getBiodata() {
    return biodata == null ? Collections.emptyList() : biodata;
}

public void setBiodata(List<String> biodata) {
    this.biodata = biodata;
}
}

And static lists (that can be compiled and won't change)

public final class BiodataHolder {

    public static final List<String> BIODATA_LIST;

    static {
        List<String> data = new ArrayList<>();
        data.add("Biodata 1");
        data.add("Biodata 2");
        // ...
        data.add("Biodata 100");
        BIODATA_LIST = Collections.unmodifiableList(data);
    }
}
    public final class PartnersDataHolder {

    public static final List<String> PARTNERS_LIST;

    static {
        List<String> data = new ArrayList<>();
        data.add("Partner 1");
        data.add("Partner 2");
        // ...
        data.add("Partner 100");
        PARTNERS_LIST = Collections.unmodifiableList(data);
    }
}
    public final class CompanyDataHolder {

    public static final List<String> COMPANY_LIST;

    static {
        List<String> data = new ArrayList<>();
        data.add("Company 1");
        data.add("Company 2");
        // ...
        data.add("Company 100");
        COMPANY_LIST = Collections.unmodifiableList(data);
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ This seems a clear way to populate them, apprecite it. \$\endgroup\$ – valkongr Nov 13 at 9:07
0
\$\begingroup\$

There are following issues with such approach:

  1. If you call getBiodata() before generateLists() you will get empty list.
  2. User of this class should know internal implementation (generateLists() breaks encapsulation).
  3. If you use setters after generateLists() you will get the state without filled data.

I would suggest following:

  1. Create dedicated private method init() and use it in constructors.
  2. Remove setters, make the lists final.
  3. Return copy of the lists, it will protect state of the class from unexpected modifications.
  4. Add dedicated methods for lists modifications.

Have a look at the following code:

public class MassiveDTO {
    private final List<String> company;
    private final List<String> partners;
    private final List<String> biodata;

    public MassiveDTO() {
        this(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
    }

    public MassiveDTO(List<String> company, List<String> partners, List<String> biodata) {
        super();
        this.company = company;
        this.partners = partners;
        this.biodata = biodata;
        init();
    }

    private void init() {
        company.add("X0788");
        company.add("X0192");
        partners.add("X0081");
        biodata.add("X0913");
    }

    public List<String> getCompany() {
        return new ArrayList<>(company);
    }

    public List<String> getPartners() {
        return new ArrayList<>(partners);
    }

    public List<String> getBiodata() {
        return new ArrayList<>(biodata);
    }

    public MassiveDTO addPartner(String partner) {
        partners.add(partner);
        return this;
    }

    public MassiveDTO addCompany(String comp) {
        company.add(comp);
        return this;
    }

    public MassiveDTO addBiodata(String bio) {
        biodata.add(bio);
        return this;
    }
}
\$\endgroup\$
  • \$\begingroup\$ I get it, but I expected something more..elegant I must say? Like a design pattern that handles data. \$\endgroup\$ – valkongr Nov 11 at 11:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.