Setting "plumbing" at runtime

This is a kind of design pattern question in Java.

I am developing a java .jar file to act as the basis for managing and processing a particular form of data. I want the end user to be able to dictate the plumbing configuration in certain constraints in a certain way. Parts are producers and / or consumers, and I know how to implement them, but the connections bother me ... here is an example of nonsense, sort of like parallels my application.

Suppose I implemented these elements:

  • AppleTree => produces apples
  • ApplePieMaker => consumes apples, produces apple pies
  • ApplePress => consumes apples, produces apple cider.
  • AppleSave => stores apples, apple pies or apple cider to a file
  • AppleLoad => "restores" apples, apple pies or apple cider from a file created AppleSave
  • ApplePieMonitor => displays apple pies on the screen in a graphical interface format, as they are created

Now I want the user to be able to specify things like:

  • AppleTree | ApplePress | AppleSave cider1.sav (produce apples, turn them into cider, save them to a file)
  • AppleTree | AppleSave apple1.sav (produce apples, save them to a file)
  • AppleLoad apple1.sav | ApplePieMaker | ApplePieMonitor (take the saved apples, make them into cakes, show the results on the screen in the graphical interface)
  • (not sure how to illustrate this, but may be indicated as follows)

    AppleTree tree1, ApplePieMaker piemaker1 <tree1, AppleSave apples.sav <tree1, AppleSave @select (*. Sav) <piemaker1, ApplePress press1 <tree1, AppleSave cider.sav <press1, ApplePieMonitor piemon1 <piemaker1

( , , , , , , , )

, , : , , 1 1 , , , , , .

, , . , , AppleConsumer, ApplePieConsumer .., ApplePieMaker AppleConsumer ( consumeApple()) AppleTree AppleProducer, , , AppleTree , consumeApple() , AppleTree, , ....

? ? .

edit: Java. ( , ) , , , , . , , -.

+3
5

, Java, . , , ( , ?), .

( ) : (, , , , , ).

public interface Filter<Input extends Type, Output extends Type> {

  public Class<Input> getInputType();

  public Class<Output> getOutputType();

  public void process(Input in, Output out);

}

- () Filter s. , , , , , , . , .

, () . , . "" () , , .

, , , , :

public interface Filter<Input extends Type, Output extends Type> {

   public Class<Input> getInputType();

   public Class<Output> getOutputType();

   public Output out process(Input in);

}

, :

public class CompoundFilter<Input extends Type, Output extends Type>
       implements Filter<Input extends Type, Output extends Type> {

  private final Filter<Input extends Type, ? extends Type> l;
  private final Filter<Input extends Type, ? extends Type> r;

  public <Median extends Type> CompoundFilter(
         Filter<Input, Median> r,
         Filter<Median, Output> l
      ) {
      this.l = l;
      this.r = r;
  }

  @SuppressWarnings("unchecked")
  public Output out process(Input in) {
      // Compute l(r(in)) = (l o r) (in)
      return ((Output<Input,Type>) l).process(r.process(in));
  }
}

, - :

Filter<A,B> f1 = new FilterImpl<A,B>;;
Filter<B,C> f2 = new FilterImpl<B,C>;
// this is mathematically f2 o f1
Filter<A,C> comp = new CompoundFilter<A,C>(f1,f2);
+1

, - .

, .

/​​ Apple, .

:

  • - Apple, AppleCider, ApplePie,
  • - AppleTree, ApplePress, ApplePieMaker, AppleLoad,
  • - ApplePress ( ), ApplePieMaker ( ), AppleMonitor, AppleSave.

, , .

, , .

 element1 | element2 | element3 <parameters> | element 4

, .

,

map.put( "AppleTree", YouAppleTreeClass.class );

, , :

for( String item: line )  { 
    Object o = map.get( item ).newInstance();
}

, , :

  • -
  • ( , )

, , .

-, , :

  • (, /)
  • ( AppleTree)

: - , , , , , , .

, . , ( ).

:

, ( , , , )

, .

/**
 * Anything. An apple, cider, pie, whatever.
 */
interface Product{}

// The kinds of products. 
class Apple     implements Product{}
class ApplePies implements Product{}
class AppleCider implements Product{}

/**
 * This indicates the class will do something.
 **/
interface Producer { 
    // adds a consumer to the list.
    public void addConsumer( Consumer c );
    // removes the consumer from the list.
    public void removeConsumer( Consumer c );
    // let know eveytone a product has been created.
    public void notifyProductCreation( Product someProduct );
    // You're producer? Produce then... 
    public void startProduction();
}

// To avoid copy/paste all around
class AbstractProducer implements Producer { 
    private List<Consumer> consumers = new ArrayList<Consumer>();
    // adds a consumer to the list.
    public void addConsumer( Consumer c ) {
        consumers.add( c );
    }
    // removes the consumer from the list.
    public void removeConsumer( Consumer c ) {
        consumers.remove( c );
    }
    public void notifyProductCreation( Product someProduct ) { 
        for( Consumer c : list ) { 
            c.productCreated( someProduct );
        }
    }
}

interface Consumer { 
    // Callback to know a product was created
    public void productCreated( Product p );
}


class AppleTree extends AbstractProducer { 
    public void startProduction() { 
        // do something with earh, sun, water.. 
        // and from time to time:
        Product ofThisNewApple = new Apple();
        notifyProductCreation( ofThisNewApple );
    }

}    
class ApplePieMaker extends AbstractProducer implements Consumer { 

    // Ok, a product was created, but
    // is it the product I care?
    // check first and consume after.
    public void productCreated( Product p ){
        // Is this the kind of product I can handle..
        // well do handle
        if( p instanceof Apple ) {
            /// start producing pies..
        }
    }
    public void startProduction() { 
        // collect the needed number of apples and then...
        Product ofPie = new ApplePie();
        notifyProductCreation( ofPie );
    }

}
class ApplePress extends AbstractProducer implements Consumer { 
    // Yeap, something gots produced.
    // Just handle if it is an apple
    public void productCreated( Product p ) { 
        if( p instanceof Apple ) { 
            // start producing cider
        }
    }


    public void startProduction() { 
        // collect the needed number of apples and then...
        Product ofCiderBottle = new AppleCider();
        notifyProductCreation( ofCiderBottle );
    }


}
class AppleSave implements Consumer { 
    public void productCreated( Product p ) { 
        file.append( p );// any one will do.
    }
}

class AppleLoad extends AbstractProducer { 
    public void startProduction() { 
        readFromFile();
    }
    private readFromFile() { 
        for( Product p : file ) { 
            notifyProductCreation( p );  
        }
    }
}


class Main { 
    public static void main( String [] args ) { 
        Configuration conf = new Configuration();
        List<Producer> producers conf.read();
        for( Producer p : producers ) { 
            // fasten your seat belts.... 
            p.startProduction();
        }
    }
}

/// Ahhh, pretty ugly code below this line.
// the idea is:
// Read the configuration file
// for each line split in the "|"
// for each element create a new instance
// and chain it with the next.
// producer | consumer | etc...  
// Becomes....
// new Producer().addConsumer( new Consumer() );
// Return the list of create producers.  
class Configuration { 
    List<Producer> producers
    // read the file 
    // create the instances
    // let them run.
    public List<Producer> read() { 
        File file = new File(....
        // The format is: 
        // producer | consumer-producer <params> | consumer 
        String line = uniqueLineFrom( file );

        String [] parts = line.split("|");

        if( parts.length == 1 ) { 
            System.err.println("Invalid configuration. use element | element | etc. Only one element was....");
            System.exit( 1 );
        }



        int length = parts.length;
        for( int i = 0 ; i < parts.length ; i++ ) { 
            Object theInstance = implementationMap.get( parts[i] ).newInstance();
            validatePosition( i, length, theInstance , parts[i] );
        }

        List<Producer> producers = new ArrayList<Producer>();
        for( int i = 0 ; i < parts.length ; i++ ) { 
            Object theInstance = getInstance( parts[i] );
            if( not( isLast( i, length ) && isProducer( theInstance ) ) { 
                // the next is its consumer
                Producer producer = ( Producer ) theInstance;
                producer.addConsumer( ( Consumer )  getInstance( parts[i+1] ));
                producers.add( producer );
            }
        }
        return producers;

    }
    // creates a new instance from the implementation map.
    private Object getInstance( String key ) { 
        return implementationMap.get( part[i] ).newInstance();        
    }
    // validates if an element at the given position is valid or not.
    // if not, prints the message and exit.
    // the first element most be a producer
    // the last one a consumer 
    // all the middle elements producer-consumer
    // 
    private void validatePosition( int i, int length, Object theInstance, String element  ) { 
        if( isFirst( i ) && not(isProducer(( theInstance ) ))) {  
            System.err.println( "Invalid configuration: " + element + " most be a producer ( either Ap...");
            System.exit( 2 );
        } else if ( isLast( i, length ) && not( isConsumer( theInstance  ))) { 
            System.err.println( "Invalid configuration: " + element + " most be a consumer ( either Ap...");
            System.exit( 3 );
        } else if ( isMiddleAndInvalid( i, length , instance ) ) { 
            System.err.println( "Invalid configuration: " + element + " most be a producer-consumer ( either Ap...");
            System.exit( 4 );
        }
    }
    private static Map<String,Class> implementationMap = new HashMap<String,Class>() static { 
        implementationMap.put( "AppleTree", AppleTree.class );
        implementationMap.put( "ApplePieMaker ", ApplePieMaker .class );
        implementationMap.put( "ApplePress", ApplePress.class );
        implementationMap.put( "AppleSave", AppleSave.class );
        implementationMap.put( "AppleLoad", AppleLoad.class );
        implementationMap.put( "ApplePieMonitor", ApplePieMonitor.class );
    };

    // Utility methods to read better ( hopefully ) the statements 
    // If you could read the validations above you may ignore these functions.


    private boolean not( boolean value ) { 
        return !value;
    }
    private boolean isFirst( int i  ) { 
        return i == 0;
    }
    private boolean isLast( int i, int l ) { 
        return i == l -1 ;
    }
    private boolean isProducer( Object o ) { 
        return o instanceof Producer;
    }
    private boolean isConsumer( Object o ) { 
        return o instanceof Consumer;
    }
    private boolean isMiddleAndInvalid( int index, int length, Object instance ) { 
        return not( isFirst( index ) ) && not( isLast( index, length ) ) && not( isProducer( instance ) && isConsumer( instance ));
    }
}
+1

, , , Spring. , : " X, Y, -, Y, , , ".

, , .

0

Java Beanshell.

BeanShell - , , Java , Java. BeanShell Java , , , Perl JavaScript.

0

- , (, ), , - . , . - , JMX, Object JMX , , (/). OSGi, .

0

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


All Articles