Bad practice is to return a common element in an abstract class of different common parameters

I have this abstract class, where I defined some methods that implement database actions (row fetching, insertion, deletion, etc.)

Now I want to make a method that will return some rows (i.e. the whole table), but instead of the domain classes, I want it to return the corresponding model classes (which are basically the same as the domain, but without the link lists and some other things that I don’t need for the presentation layer).

Abstract class

public abstract class DomainService<T extends Domain> { protected abstract Logger getLogger(); protected final Validator validator; protected DomainService() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); this.validator = factory.getValidator(); } abstract public void insert(T object) throws ValidationException; abstract public void delete(T object) throws EntityNotFoundException; abstract public List<T> fetchAll(); } 

and I want to add another method that will call fetchAll() , and then fetchAll() each element and create an equivalent model and return this list.

 public <K extends Model> List<K> fetchAllModels(Class<K> modelClass) { List<T> domains = fetchAll(); List<K> models = new ArrayList<K>(domains.size()); for ( T domain : domains) { K model = modelClass.newInstance(); models.add(model.fillIn(domain)); } return models; } 

Ignoring the fact that this is code, although I am just writing a question whether it is permissible to add a parameter for a general type that is not defined in the class. An IMO class may have methods that return other data types, so this should not be a problem. In my case, I pass the class to instantiate the model, and then use the domain to populate the members. I had two opinions,

  • I wrote where I add a method to a model class to create it myself from a domain object. I was thinking of a constructor that takes a domain object as an argument, but I think it’s a bit of a hassle to call a constructor using generics (this will require at least reflection utilities), so although I use a method to populate Details after creating the instance using the default constructor. In addition, the model is at a higher level, and I think higher levels should use lower ones (Database-> Domain classes-> Access classes (DAO) β†’ Service classes-> servlet classes ----> JSP showing data)

  • I could add a method to a domain class that converts the domain to its model and calls it without passing the model class

     public <K> List<K> fetchAllModels() { List<T> domains = fetchAll(); List<K> models = new ArrayList<K>(domains.size()); for ( T domain : domains) { models.add(domain.createModel()); } return models; } 

but I believe that the domain class should be as clean as representing the table in the database using only the methods associated with the columns.

It would be better to add a parameter to the class. I'm only going to use it for this method ...

Any thoughts are always welcome.

+6
source share
1 answer

it is permissible to add a parameter for a general type that is not defined in the class

That's right. This has been done all the time.

I prefer your first solution, passing the model to the method.

But what you really want is a function that creates K from T. In java8, this can be done very succinctly.

 public <K extends Model> List<K> fetchAllModels(Function<T,K> func) { ... K model = func.apply(domain); 

and say that you have a model β€œM” for domain β€œD”

 public M(D domain) // constructor 

you can pass the constructor as func (or at least it seems so)

  service.fectchAllModels( M::new ) 

If you use Stream , fetchAllModels() gets a lot easier

 abstract public Stream<T> fetchAll(); public <K extends Model> Stream<K> fetchAllModels(Function<T,K> func) { return fetchAll().map(func) } 

And then, why do we need this method? Just do

 // fetch domains, convert each to M Stream<M> models = service.fetchAll().map( M::new ); 

So, we can remove fetchAllModels() and remove any model dependencies from the domain.

+4
source

Source: https://habr.com/ru/post/987510/


All Articles