POJO z finalnymi atrybutami

0

Jak mam 7 atrybutów klasy POJO, finalne inicjowane w konstruktorze to lepiej robić konsturktor z 7 parametrami obowiązkowymi czy buildera?

2

Wg mnie wtedy lepiej

  • nauczyć się Kotlina
  • zdefiniować sobie POJO z domyślnymi parametrami w data classie
  • zapomnieć o builderach i tworzyć sobie obiekty jak człowiek, z tymi parametrami których akurat potrzebujesz
  • side note: data class daje Ci gotową metodę copy() z możliwością nadpisania wybranych parametrów w kopii obiektu
0

Napisanie buildera, który zapewnia ci parametry obowiązkowe (i to 7) nie jest takie proste :). Jak masz aż 7 parametrów to znak ze cos jest nie tak z twoim POJO, chyba ze to szpring :) Lombok może być pomocny ;)

0

Jest 7 atrybutów, bo to końcowy produkt całej apki, który następnie jest konwertowany i w całości ładowany do Mongo.

0

Najpierw sprawdź, czy nie możesz wyodrębnić innej klasy z tych parametrów. Np. klasa User dostaje firstName, secondName, surname. Te trzy pola można z powodzeniem przerzucić do klasy UserName i ją wstrzykiwać przez konstruktor do klasy User. Jeśli nadal to nie wystarcza to idź w buildera.

0
superdurszlak napisał(a):

Wg mnie wtedy lepiej

  • nauczyć się Kotlina
  • zdefiniować sobie POJO z domyślnymi parametrami w data classie
  • zapomnieć o builderach i tworzyć sobie obiekty jak człowiek, z tymi parametrami których akurat potrzebujesz
  • side note: data class daje Ci gotową metodę copy() z możliwością nadpisania wybranych parametrów w kopii obiektu

W javie 12 jest coś podobnego - zamiast data class masz record. :) Chociaż nie wiem czy będzie odpowiednik copy
EDIT: miało być coś podobnego, jednak to nie prawda; @Wibowit dzięki za sprostowanie

0

Pokażę Wam na kodzie o co chodzi.

Było tak:

public interface Result {

	boolean isValid();

	ResultSalary getSalary();

	Optional<Integer> getWorkExpInMonths();

	Set<String> getTech();

	Optional<String> getArea();	

	Optional<Integer> getAge();

	Optional<ContractType> getContractType();
}
final class ResultImpl implements Result {

	private final boolean isValid;
	private final MessageSalary salary;
	private final Optional<Integer> experience;
	private final Set<String> technologies;
	private final Optional<String> location;
	private final Optional<Integer> age;
	private final Optional<ContractType> contractType;

	public ResultImpl (String content) {
		Scrapper<Integer> scrapperExp = new ScrapperExpFactory().produceDefault();
		Scrapper<String> scrapperTech = new ScrapperTechFactory().produceDefault();
		Scrapper<String> scrapperLocation = new ScrapperLocationFactory().produceDefault();
		Scrapper<Integer> scrapperAge = new ScrapperAgeFactory().produceDefault();
		Scrapper<ContractType> scrapperContractType = new ScrapperContractTypeFactory().produceDefault();

		this.salary = new MessageSalary4programmers(content);
		this.experience = scrapperExp.scrapeFrom(content).stream().min(Comparator.naturalOrder());
		this.technologies = new HashSet<String>(scrapperTech.scrapeFrom(content));
		this.location = scrapperLocation.scrapeFrom(content).stream().findFirst();
		this.age = scrapperAge.scrapeFrom(content).stream().findFirst();
		this.contractType = scrapperContractType.scrapeFrom(content).stream().findFirst();
		this.isValid = salary.getValueMonth().isPresent() && experience.isPresent() && technologies.size() > 0;
	}

	@Override
	public boolean isValid() {
		return this.isValid;
	}

	@Override
	public MessageSalary getSalary() {
		return this.salary;
	}

	@Override
	public Optional<Integer> getWorkExpInMonths() {
		return this.experience;
	}

	@Override
	public Set<String> getTech() {
		return technologies;
	}

	@Override
	public Optional<String> getArea() {
		return location;
	}

	@Override
	public Optional<Integer> getAge() {
		return age;
	}

	@Override
	public Optional<ContractType> getContractType() {
		return contractType;
	}
}
interface ResultSalary {
	
	Optional<Integer> getValueMonth();

	Optional<NettoBruttoSalary> getNettoBrutto();

	Optional<CurrencySalary> getCurrency();

	double getExchangeRate();
}
final class ResultSalaryImpl implements ResultSalary {

	private final Optional<Integer> value;
	private final Optional<NettoBruttoSalary> netGross;
	private final Optional<CurrencySalary> currency;
	private final double exchangeRate;

	public ResultSalaryImpl (String content) {
		Scrapper<Integer> scrapperSalaryValue = new ScrapperSalaryValueFactory().produceDefault();
		Scrapper<NettoBruttoSalary> scrapperNetGross = new ScrapperNetGrossFactory().produceDefault();
		Scrapper<CurrencySalary> scrapperCurrency = new ScrapperCurrencyFactory().produceDefault();

		this.value = scrapperSalaryValue.scrapeFrom(content).stream().findFirst();
		this.netGross = scrapperNetGross.scrapeFrom(content).stream().findFirst();
		this.currency = scrapperCurrency.scrapeFrom(content).stream().findFirst();
		this.exchangeRate = currency.isPresent() ? 
				(GlobalDataHolder.CURRENCIES.getMap().get(currency.get().toString())) : 1.0;
	}

	@Override
	public Optional<Integer> getValueMonth() {
		return value;
	}

	@Override
	public Optional<NettoBruttoSalary> getNettoBrutto() {
		return netGross;
	}

	@Override
	public Optional<CurrencySalary> getCurrency() {
		return currency;
	}

	@Override
	public double getExchangeRate() {
		return exchangeRate;
	}
}

zamieniłem na:

public final class Result {

	public final boolean isValid;
	public final MessageSalary salary;
	public final Optional<Integer> experience;
	public final Set<String> technologies = new HashSet<>();
	public final Optional<String> location;
	public final Optional<Integer> age;
	public final Optional<ContractType> contractType;
	
	public Result(Builder builder) {
		this.isValid = builder.isValid;
		this.salary = builder.salary;
		this.experience = builder.experience;
		this.technologies.addAll(builder.technologies);
		this.location = builder.location;
		this.age = builder.age;
		this.contractType = builder.contractType;
	}
	
	public static class Builder {
		boolean isValid;
		MessageSalary salary;
		Optional<Integer> experience;
		Set<String> technologies;
		Optional<String> location;
		Optional<Integer> age;
		Optional<ContractType> contractType;
		
		public Builder setValid(boolean isValid) {
			this.isValid = isValid;
			return this;
		}
		
		public Builder setMessageSalary(MessageSalary salary) {
			this.salary = salary;
			return this;
		}
		
		public Builder setExperience(Optional<Integer> experience) {
			this.experience = experience;
			return this;
		}
		
		public Builder setTechnologies(Set<String> technologies) {
			this.technologies = technologies;
			return this;
		}
		
		public Builder setLocation(Optional<String> location) {
			this.location = location;
			return this;
		}
		
		public Builder setAge(Optional<Integer> age) {
			this.age = age;
			return this;
		}
		
		public Builder setContractType(Optional<ContractType> contractType) {
			this.contractType = contractType;
			return this;
		}
		
		public Result build() {
			return new Result(this);
		}
	}
}
interface ResultFactory {

	Result createResult(String content);
}
final class ResultFactoryImpl implements ResultFactory {

	@Override
	public ResultFactoryImpl createResult(String content) {
		Scrapper<Integer> scrapperExp = new ScrapperExpFactory().produceDefault();
		Scrapper<String> scrapperTech = new ScrapperTechFactory().produceDefault();
		Scrapper<String> scrapperLocation = new ScrapperLocationFactory().produceDefault();
		Scrapper<Integer> scrapperAge = new ScrapperAgeFactory().produceDefault();
		Scrapper<ContractType> scrapperContractType = new ScrapperContractTypeFactory().produceDefault();

		MessageSalary salary = new MessageSalary4programmersFactory().createMessageSalary(content);
		Optional<Integer> experience = scrapperExp.scrapeFrom(content).stream().min(Comparator.naturalOrder());
		Set<String> technologies = new HashSet<String>(scrapperTech.scrapeFrom(content));
		Optional<String> location = scrapperLocation.scrapeFrom(content).stream().findFirst();
		Optional<Integer> age = scrapperAge.scrapeFrom(content).stream().findFirst();
		Optional<ContractType> contractType = scrapperContractType.scrapeFrom(content).stream().findFirst();
		boolean isValid = salary.value.isPresent() && experience.isPresent() && technologies.size() > 0;
		
		return new Result.Builder()
				.setMessageSalary(salary)
				.setExperience(experience)
				.setTechnologies(technologies)
				.setLocation(location)
				.setAge(age)
				.setContractType(contractType)
				.setValid(isValid)
				.build();
	}
}
final class ResultSalary {
	 
	public final Optional<Integer> value;
	public final Optional<NetGrossSalary> nettoBrutto;
	public final Optional<CurrencySalary> currency;
	public final double exchangeRate;
	
	public ResultSalary (Builder builder) {
		this.value = builder.value;
		this.nettoBrutto = builder.nettoBrutto;
		this.currency = builder.currency;
		this.exchangeRate = builder.exchangeRate;
	}
	
	public static class Builder {
		Optional<Integer> value;
		Optional<NetGrossSalary> nettoBrutto;
		Optional<CurrencySalary> currency;
		double exchangeRate;
		
		public Builder setValue(Optional<Integer> value) {
			this.value = value;
			return this;
		}
		
		public Builder setNettoBrutto(Optional<NetGrossSalary> nettoBrutto) {
			this.nettoBrutto = nettoBrutto;
			return this;
		}
		
		public Builder setCurrency(Optional<CurrencySalary> currency) {
			this.currency = currency;
			return this;
		}
		
		public Builder setExchangeRate(double exchangeRate) {
			this.exchangeRate = exchangeRate;
			return this;
		}
		
		public ResultSalary build() {
			return new ResultSalary(this);
		}
	}
}
interface MessageSalaryFactory {

	MessageSalary createResultSalary(String content);
}
final class ResultSalaryFactoryImpl implements ResultSalaryFactory {

	@Override
	public ResultSalaryFactoryImpl createResultSalary(String content) {
		Scrapper<Integer> scrapperSalaryValue = new ScrapperSalaryValueFactory().produceDefault();
		Scrapper<NetGrossSalary> scrapperNetGross = new ScrapperNetGrossFactory().produceDefault();
		Scrapper<CurrencySalary> scrapperCurrency = new ScrapperCurrencyFactory().produceDefault();

		Optional<Integer> value = scrapperSalaryValue.scrapeFrom(content).stream().findFirst();
		Optional<NetGrossSalary> netGross = scrapperNetGross.scrapeFrom(content).stream().findFirst();
		Optional<CurrencySalary> currency = scrapperCurrency.scrapeFrom(content).stream().findFirst();
		double exchangeRate = currency.isPresent() ? 
				(GlobalDataHolder.CURRENCIES.getMap().get(currency.get().toString())) : 1.0;
				
		return new ResultSalaryFactory.Builder()
				.setValue(value)
				.setNettoBrutto(netGross)
				.setCurrency(currency)
				.setExchangeRate(exchangeRate)
				.build();
		
	}
}

Chyba źle zrobiłęm, bo 120 linijek zaminiłem na 180

1

W przykładzie z interfejsem możesz użyć biblioteki Immutables, która generuje automatycznie implementację i builder. Ewentualnie możesz użyć lomboka. Najlepiej jednak jest wybrać np. Kotlina zamiast pluginów do kompilatora. Kotlin w sumie też jest pluginem do kompilatora, tylko stabilniejszym i lepiej udokumentowanym

1 użytkowników online, w tym zalogowanych: 0, gości: 1