2

I have various classes that extend a single class, NormalizedTransfer, where I want to store some data (and do some other things, like transfer the list of normalizations somewhere). The parent class is:

public abstract class NormalizedTransfer
{
  protected final List< Normalized > normalizedList = new ArrayList<>();
}

...and subclasses are defined like this:

public class BundleNormalizer extends NormalizedTransfer...
public class PatientNormalizer extends NormalizedTransfer...
public class ObservationNormalizer extends NormalizedTransfer...
public class ProcedureNormalizer extends NormalizedTransfer...
public class EncounterNormalizer extends NormalizedTransfer...

Each of the subclasses does something like this:

public class BundleNormalizer extends NormalizedTransfer
{
  public void normalize()
  {
    normalizedList.add( new Normalized( /* some specification of a normalization accomplished */ ) );
  }
}

Here, I show a simplified version of those classes (for bundles) after the essence of NormalizedTransfer which is supposed to hold all discovered normalizations of all normalizers (and do other stuff), PatientNormalizer, ObservationNormalizer, etc. (plus BundleNomalizer, obviously). Only, when I analyse a the next patient in a document, and instantiate a new PatientNormalizer, the normalizedList of NormalizedTransfer is a different list that the one for a bundle, than the other one for an observation, etc.

Of course it is; I know this. I'm probably looking for a "pattern" to implement.

Also, all of this code will be executed by myriad other threads handling each a separate medical document. So, what I'm asking for is a single (simple) database (ArrayList) bookkeeping a list of normalizations that I'm recording for a whole document no matter what the type and how many resources (patients, observations, accounts, etc.) are encountered. And it can't have anything to do with whatever's being found in other documents.

Russ Bateman
  • 18,333
  • 14
  • 49
  • 65
  • 2
    Can't you make normalizers return what they compute, and aggregate it in an external list ? Like : `interface Normalizer { Normalized normalize(Document toAnalyze); }` ? Then make a list of available normalizers and launch computation upon the doc : `List results = allNormalizers.stream().map(n -> n.normalize(doc)).collect(Collectors.toList());`. Maybe there's constraint in your program that I don't know, though. – amanin Jan 15 '21 at 18:07
  • (Sorry, you're right and I have fixed the misspellings.) – Russ Bateman Jan 15 '21 at 20:20

2 Answers2

2

I'd adapt the naming: ...Transmitter instead of ...Transfer since transfer is a process, not the thing that performs it.

I'd decouple things since the task of a transmitter is to transmit, not to hold data.

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

public class NormalizedList<T> extends AbstractList<T> {

    List<T> list = new ArrayList<>();

    @Override
    public void add( final int index, final T element ) {
        list.add( index, element );
    }

    @Override
    public T get( final int index ) {
        return list.get( index );
    }

    @Override
    public T remove( final int index ) {
        return list.remove( index );
    }

    @Override
    public int size() {
        return list.size();
    }

    void transmitWith( final Class<?> clazz ) throws NoSuchMethodException, SecurityException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    clazz.getMethod( "transmit", List.class ).invoke( null, this );
    }
}
public class NormalizedTransmitter {

    public static void transmit( final List<?> list ) {
        System.out.printf( "NormalizedTransmitter transmitting %d items of %s...%n",
                list.size(), list.getClass().getName() );
    }
}
public class BundleNormalizer {

    private final List<Object> list;

    // constructor injection here, but any other injection method is conceivable
    public BundleNormalizer( final List<Object> list ) {
        this.list = list;
    }

    public void normalize() {
        list.add( new Object( /* some specification of a normalization accomplished */ ) );
    }
}
public class Main {

    public static void main( final String[] args ) {

        final NormalizedList<Object> list = new NormalizedList<>();

        new BundleNormalizer( list ).normalize();
        new BundleNormalizer( list ).normalize();

        NormalizedTransmitter.transmit( list );
        // output: NormalizedTransmitter transmitting 2 items of NormalizedList...

        list.transmitWith( NormalizedTransmitter.class );
        // output: NormalizedTransmitter transmitting 2 items of NormalizedList...
    }
}

If you want you can make your NormalizedList a Singleton to be safe that there's really just one.

import java.util.ArrayList;
import java.util.List;

public enum NormalizedListSingleton {
    INSTANCE;

    List<Object> list = new ArrayList<>();

    public void add( final Object element ) {
        list.add( element );
    }

    public void add( final int index, final Object element ) {
        list.add( index, element );
    }

    public Object get( final int index ) {
        return list.get( index );
    }

    public Object remove( final int index ) {
        return list.remove( index );
    }

    public int size() {
        return list.size();
    }
}
public class PatientNormalizer {

    private final NormalizedListSingleton list;

    // constructor injection here, but any other injection method is conceivable
    public PatientNormalizer( final NormalizedListSingleton list ) {
        this.list = list;
    }

    public void normalize() {
        list.add( new Object( /* some specification of a normalization accomplished */ ) );
    }
}
public class NormalizedTransmitter {

    // ...

    public static void transmit( final NormalizedListSingleton list ) {
        System.out.printf( "Transmitting %d items of %s...%n", list.size(), list.getClass().getName() );
    }
}
public class Main {

    public static void main( final String[] args ) {

        // ...

        new PatientNormalizer( NormalizedListSingleton.INSTANCE ).normalize();
        new PatientNormalizer( NormalizedListSingleton.INSTANCE ).normalize();

        NormalizerTransmitter.transmit( NormalizedListSingleton.INSTANCE );
        // output: Transmitting 2 items of NormalizedListSingleton...
    }
}
Gerold Broser
  • 14,080
  • 5
  • 48
  • 107
  • If using a singleton, analysis of every documents will end up in the same list, and if I've read correctly the question, it's not what is wanted. Also, can you explain what the NormalizedList class is needed for ? What concept/purpose it fit ? Why not using an ArrayList directly ? – amanin Jan 16 '21 at 19:03
  • @amanin 1) Re singleton: There's "_NormalizedTransfer which is supposed to hold all discovered normalizations of all normalizers_" in the Q. With that I interpreted the next sentence with "_Only, when ..._" as the current situation which shouldn't be. 2) You're right. That's not an MCVE. With `NormalizedList` I wanted to express that you dont' have to introduce a has-a relationship (for a special purpose list in this case) but that you can define a special purpose list itself as a loosely coupled component (that maybe has additional processing, e.g. `void transmitWith(Transmitter t) {...}`). – Gerold Broser Jan 16 '21 at 19:45
1

So are you trying to collect all the information into one base List? If so, make a getter for that parent class that is public. Then the classes that extend it just use

super.getMyListName().add(whateverObjectYouWantToAdd);

of course your getter in your parent is

public List getMyListName(){
     return myListName; // call if whatever you want of course.
}
Dale
  • 1,613
  • 4
  • 22
  • 42