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.
3 Answers 3
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();
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);
}
}
-
1\$\begingroup\$ This seems a clear way to populate them, apprecite it. \$\endgroup\$Manuel Pap– Manuel Pap2019年11月13日 09:07:17 +00:00Commented Nov 13, 2019 at 9:07
There are following issues with such approach:
- If you call
getBiodata()
beforegenerateLists()
you will get empty list. - User of this class should know internal implementation (
generateLists()
breaks encapsulation). - If you use setters after
generateLists()
you will get the state without filled data.
I would suggest following:
- Create dedicated private method
init()
and use it in constructors. - Remove setters, make the lists final.
- Return copy of the lists, it will protect state of the class from unexpected modifications.
- 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;
}
}
-
\$\begingroup\$ I get it, but I expected something more..elegant I must say? Like a design pattern that handles data. \$\endgroup\$Manuel Pap– Manuel Pap2019年11月11日 11:05:08 +00:00Commented Nov 11, 2019 at 11:05
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\$