Condivisione di POJO tra diversi gestori

2

I am trying to automate Business Process which can be characterized as a pipeline with distinct stages.

Pipeline can be perceived as A->B->C, where A,B,C are distinct Business Steps that work on some common POJO.

Ad esempio, consideriamo questo processo aziendale:

Business needs to identify whether a Book can be sold in Indian Subcontinent.

Step 1. Ensure that the Book has a specific Publisher P

Step 2. Fetch all editions of Book. The book can only be sold if the edition is > 2.0

Step 3. Make sure that the Price is < 5k. If not check with the Publisher.

Questa è una pipeline semplice con 3 passaggi. Questi passaggi sono diversi l'uno dall'altro e dovrebbero essere progettati per una facile riutilizzabilità. For example, if tomorrow I need to work on a similar logic for US, I should be able to use Step 1, but for a different publisher.

Ho un'interfaccia come questa: -

interface Step {
  // T pojo might vary based on which business problem is being solved.
  // But the variation will be very slight. For example, different Business
  // involving Books will typically work on multiple POJO's each having attributes of Books (with slight variations) 
  <T> void process(T pojo) throws Exception;
}

Per semplicità, diciamo che abbiamo 2 distinti processi aziendali nel subcontinente indiano & in noi. Potremmo aver seguito POJO.

class IndianBooks {
  String publisher;
  int price;
  String importer; // this one is not present next POJO
  ...
}

class USBooks {
  String publisher;
  int price;
  String printedAt; //this one is different from IndianBooks
  ...
}

Ogni passo Pipeline implementerebbe questo Step Interface Ad esempio.

class FilterByPublisher implements Step {
//lets say FilterByPublisher  is invoked by Business 1, which deals with Indian Subcontinent
// 'process' method should be able to operate on IndianBooks POJO
// if invoked by Pipeline2 which opearates on US Books this method should be 
// able to handle USBooks POJO

  void process(T pojo) {
    1. needs to access publisher attribute of T
    ...
 }
}

Ho pensato al seguente modo:

  1. utilizzando instanceof nel metodo process() per verificare il tipo del POJO e quindi operare su di esso, quindi impostare l'altro attributo. %codice%

Ma in qualche modo ritengo che questo non sia un modo scalabile dato che ogni volta che una nuova pipeline entra in scena, dovrò aggiornare questo metodo.

Qualche input su come posso risolverlo efficacemente?

Aggiornamento: - Dopo aver esaminato il commento di @Jules, ho esaminato Visitor Pattern & pensato al seguente approccio.

Potrei mantenere l'interfaccia passo generica. Crea una classe Note that this change should be reflected in sub-sequent Stages astratta che gestisca la logica di filtraggio. Crea 2 classi di filtri concreti (da utilizzare in diversi processi aziendali) che gestiscono solo l'input & passa alla classe FilterByPublisher .

abstract class FilterByPublisher {
  void filter(String publisher) {
    ..
 }
}

class FilterByPublisher_IndianBusiness extends FilterByPublisher implements Step {
 @Override
 public <T> void process(T pojo) {
   String publisher = ((IndianBooks)pojo).getPublisher(); // typecast
   filter(publisher);
  }
}

Sono possibili altre alternative.

    
posta AgentX 02.05.2016 - 09:16
fonte

2 risposte

3

Il modello di progettazione / dominio è semplice sbagliato , se devi occuparti di instanceof . Si tratta di una chiara percentuale di utilizzo OOP inventata per, resp. %codice%. trattare un gruppo di oggetti diversi come una famiglia di oggetti . Ci sono due modi per risolvere il tuo problema:

1) Definisci una base comune per Polymorphism e Indian Books . Questo ha senso, quando entrambi sono effettivamente USBooks .

2) Definisci un Books che fornisce le informazioni necessarie per il filtro

Come passo successivo, dovresti rifattorizzare il filtro in un schema di strategia , quindi che sei in grado di scambiare dinamicamente i criteri del filtro.

    
risposta data 05.06.2016 - 10:34
fonte
0

Potrebbe essere reso piuttosto generico usando la riflessione e una fabbrica che usa una mappa. La mappa collega classi, che contengono funzionalità per l'elaborazione di uno o più tipi di libri, a quei tipi di libri.

I vari passaggi nel processo A- > B- > C hanno un nome e viene creato un factory con quel nome. Usando il nome del passo e la classe del libro passati alla fabbrica, la classe del passo corretta viene recuperata usando la mappa / tabella.

Quando si vuole aggiungere la funzionalità si crea la classe che contiene quella funzionalità. Quindi aggiorna la mappa / tabella in modo da associare tale funzionalità a una o più classi e passaggi del libro. Quando viene aggiunta una nuova funzionalità, l'unica modifica al codice esistente è l'aggiornamento della mappa. Anche allora la mappa dovrebbe essere esternalizzata tramite jpa, o un'iniezione a molla, ecc. Quindi non ci sono modifiche al codice, solo nuove aggiunte di classe. Se si esegue l'esternalizzazione, è possibile utilizzare il nome classe anziché l'oggetto classe per l'indicizzazione del mapping.

Interfacce:

public interface Book {

}

public interface Step {
    public void execute(Book book);
}

La fabbrica (getter e setter omessi per brevità):

public class StepFactory {

    private static final Map<String, Map<Class<Book>, Class<Step>>> map = new HashMap<>();
    // add items to the map

    private String stepName;

    public StepFactory(String stepName) {
        this.stepName = stepName;
    }

    public Step getStep(Book book) {

        Map<Class<Book>, Class<Step>> stepMap = map.get(stepName);
        if (stepMap == null) {
            // do whatever else needs to be done here
            return null;
        }

        Class<Step> stepClass = stepMap.get(book.getClass());
        if (stepClass == null) {
            // do whatever else needs to be done here
            return null;
        }

        try {
            Step step = stepClass.newInstance();
            return step;

        } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
                // do whatever else needs to be done here
                return null;
        }

    }
}

Da qualche altra parte:

StepFactory stepFactory = new StepFactory("step A");
Step step = stepFactory.getStep(book);
step.execute(book);

Le classi che implementano la funzionalità gettano ancora il libro sull'implementazione di Book che richiedono. Ma ci si aspetta che questo avvenga sulla base di una corretta mappatura.

    
risposta data 05.05.2016 - 21:49
fonte

Leggi altre domande sui tag