1
\$\begingroup\$

I have a use case where a verification batch job (non-generic) verifies domains based on its input e.g domain_type, batch_pointer etc. The verification handles it based on the domain type which uses generics.

class VerificationJob {
   public void execute() {
     String domainType = "user";
     long batchPointer = 123;

     // how to handle generics at this abstraction level to avoid using ?
     Batch<?> batch = getRepositoryInstance(domainType).fetchNextNRecords(batchPointer, 10);
     new VerificationTask(batch.contents(), (T t) -> true).verify();
     if(batch.hasNext()) {
        // schedule next job with new batch pointer
     }

   }

   Repository<?> getRepositoryInstance(String domainType) {
     return domainType.equals("user") ? new UserRepository() : null; // or a switch case etc.
   }
}


class VerificationTask<T> {
   Collection<T> ts; // construction inject 
   Predicate<T> verifier;
 
   boolean verify() {
     // verification based on verifier for each t 
   }
}


class UserRepository implements Repository<User> {
   Batch<User> fetchNextNRecords(int batchPointer, int limit) {
      // code omitted
   }
} // similarly we could have for Employee

class Repository<T> {
   Batch<T> fetchNextNRecords(int batchPointer, int limit);
}

class Batch<T> {
   List<T> contents = new ArrayList(); // getter & setter omitted
   boolean hasNext = false; // getter & setter  
}

class User {  
  // code omitted
} // similarly have for Employee

One solution I could think of is to have the generics code in another abstraction level and return the batch with verification result above. However, this will be repeated for all concrete impls e.g user, employee. Is there any other solution to solve this?


// in job class in case domainType is "user"
BatchVerificationResult result = new UserVerificationTask().verify(123, 10);
if(result.hasNext()) {
  // schedule next
}


class UserVerificationTask<User> implements BatchVerification {
  BatchVerificationResult verify(long batchPointer, int limit) {
     // do the above verification which is in job class
  }
}

interface BatchVerification {
  BatchVerificationResult verify(long batchPointer, int limit);
}

class BatchVerificationResult {
   boolean verificationResult;
   boolean hasNext;
}

```
\$\endgroup\$
0

2 Answers 2

2
\$\begingroup\$

Hmm why dont you have a batch as a collection of verification tasks and each tasks is related to a domain object.

Your current approarch is a verification task contains collection of domain objects. And inside task, you have a loop to verify each domain object.

I would prefer have a task contains only 1 object and it has responsibility to verify one task only then a batch contain a list of verification tasks that has responsibility of iterating through the collection of tasks and trigger the tasks.


Here's my suggestion:

Based on your description, there are some points need attention here:

  • Batch: a collection of verification tasks
  • Verification: a task to verify domain input.

For Batch, you should use Iterator pattern which is pretty much as what you are having.

interface Iterator<T> {
 boolean hasNext()
 T next()
}

class Batch<D> implement Iterator<VerificationTask<D>> {
...
}

For Verification, we can use either Factory pattern to produce correct verfication object based on domain class.

interface VerificationTask<D> {
  boolean isValid()
}

class UserVerificationTask implements VerificationTask<User> {
  UserVerificationTask(User domain) {this.domain = domain}
  
  boolean isValid() {...}
}

class VerificationTaskFactory {
  VerficationTask task( class input here) ...
}

Other approaches could be Strategy pattern or Template pattern, depending on how you do the verification in practice or builder if you have a lot of domain objects and they share certain same steps that can be reused.

\$\endgroup\$
1
  • \$\begingroup\$ thanks. However, due to performance reasons and nature of the real verification tasks, the suggested structure will not be appropriate. I have already used template before but, I am trying to simplify. Ref - codereview.stackexchange.com/questions/287212/… \$\endgroup\$ Sep 27 at 4:19
2
\$\begingroup\$

VerificationJob getRepositoryInstance method
Repositories encapsulate code that doesn't change between calls. The only part of code in a repository that could be call specific is persistence unit, when connecting to different persistence environments has to be supported, that turning repository into a singleton, so the method should return same instance of repository per domainType.

For unknown values of domainType returning a no-op repository instance (a repository that returns an empty Batch) would prevent testing for null before using the returned repository instance.
 
 
 
Batch hasNext variable
Using the iterator of contents list instead makes it redundant though if there are arguments supporting its use the initial value should be true.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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