Generics bei folgender Problemstellung benutzen?

chetigol0308

Grünschnabel
Hi!

ich habe diesbezüglich schon in einem anderen Forum nachgefragt, wöchte mir aber eine zweite Meinung einholen!

Folgendes Beispiel:
Es soll eine Menge unterschiedlicher Parameterklassen / Objekte geben und zu diesen können austauschbare Generatoren installiert werden.
Was alle Generatorklassen gemeinsam haben ist außer der generate - Funktion, die Referenz auf ein Parameterobjekt, da aus diesem je nach Parametertyp unterschiedliche Informationen benötigt werden. Jeder Generatortyp ist also von einem bestimmten Parametertyp abhängig.

Habe mir gedach, dass ich dieses Problem mittels Generics löse:

Code:
import java.io.*;


public final class WithGenerics {
   
// 1. Definition der Parameterklassen
    // Allgemeine Parameterklasse, auf der alle weiteren aufsetzen
    static abstract class Parameter{
       
        // unique Kennung des PArametertyps
        public int kennung;         
       
        // erwartete Parametergröße (-1 .. dynamisch)
        // kann für nachträgliche checks verwendet werden
        // bei manchen Parametertypen wird die Größe im header eingetragen
        public int size;             
       
        protected Parameter( int kennung, int size ){
            this.kennung = kennung;
            this.size    = size;
        }
    }
   
    // Spezifischer Parameter 1
    static class SystemXYParameter extends Parameter {
       
        // subkennung, gilt nur für parameter des Systems XY
        public byte subkennung;
       
        // Parametertyp (Gilt nur für SystemXY)
        public boolean common;
       
        public SystemXYParameter( int kennung, int size, byte subkennung, boolean common ){
            super( kennung, size );
           
            this.subkennung = subkennung;
            this.common = common;
        }
    }
   
    // Spezifischer Parameter 2
    static class ServiceZParameter extends Parameter{
        // Service Z mit oder ohne crcCheck
        public boolean crcCheck;
       
        public ServiceZParameter( int kennung, int size, boolean crcCheck ){
            super( kennung, size );
           
            this.crcCheck = crcCheck;
        }
    }
   
   
// Definition der Generatorklassen
    // Abstrakte Generatorklasse
    // muss zumindest mit einem gültigen Paraemtertyp parametriert werden
    static abstract class Generator<P extends Parameter>{
        public P parameter;
       
        public void setParameter( P parameter ){
            this.parameter = parameter;
        }
       
        // Bereits hier könnte ich den Generator implementiren, falls alle Generatoren eine
        // gemeinsamkeit haben! Zum Beispiel einen Header-implementierung, falls dises
        // bei allen Parametern gleich ist
        // und wenn der Header die Kennung und die erwartete Größe enthalten sollte,
        // so kann ich dies auch gleich hier erledigen, da alle weiteren Generatoren zumindest
        // mit der "Parameter" - Klasse parametrisiert werden müssen!
        public abstract void generate( OutputStream out );
    }
   
   
    // 1. Generatoren für Parameter des SystemXY
    // --> normal würden diese klassen eine gemeinsame superklasse haben, aber ich lass das
    // jetzt mal
    static class GeneratorSystemXYSubPar1 extends Generator<SystemXYParameter>{
       
        @Override
        public void generate(OutputStream out ){
            PrintStream data =  new PrintStream(out);
           
            // schreibe Parameterstruktur in den Stream
            //....

            //1. zugriff auf die members der super - Klasse
            data.print( parameter.kennung );
            data.print( parameter.size );
            // 2. zugriff auf die erweiterten Parameter fürs SystemXY
            data.print( parameter.subkennung );
            data.print( parameter.common );

            // 3....schreibe eigentliche parameterdaten ( aus Database, File,...je nach generator)
        }
    }
   
    // Generator für das SystemXY, SubParameter2
    static class GeneratorSystemXYSubPar2 extends Generator<SystemXYParameter>{
       
        @Override
        public void generate(OutputStream out ){
           
            PrintStream data =  new PrintStream(out);
           
            // schreibe Parameterstruktur in den Stream
            //....
            //1. zugriff auf die members der super - Klasse
            data.print( parameter.kennung );
            data.print( parameter.size );
            // 2. zugriff auf die erweiterten Parameter fürs SystemXY
            data.print( parameter.subkennung );
            data.print( parameter.common );
            // 3....schreibe eigentliche parameterdaten ( aus Database, File,...je nach generator)
            //      Die PArameterstruktur für die SubParameter unterscheiden sich voneinader
            //      dehalb unterschiedliche Generatoren
        }
    }
   
   
    public static void main(String[] args) {
   
        // 1. erzeuge einen neuen Generator für das System XY SupPArameter 1
        GeneratorSystemXYSubPar1 gen1 = new GeneratorSystemXYSubPar1();
        // 2. teile dem generator einen parameter zu
        //    Kennung: 0, size: 40000 Byte, subkennung: 1, common: true
        gen1.setParameter( new SystemXYParameter( 0, 40000, (byte)1, true) );
       
        // erzeuge einen weiteren Geberator für das System XY und den SbParameter 2
        GeneratorSystemXYSubPar2 gen2 = new GeneratorSystemXYSubPar2();
        // Teile dem Generator ein PAraemterobjekt zu
        //  Kennung: 1, size: 39 Byte, subkennung: 2, common: false
        gen2.setParameter( new SystemXYParameter( 1, 39, (byte)2, false) );
       
        // generiere paraemter 1
        gen1.generate( System.out );
       
        System.out.println();
       
        // generiere paraemter 2
        gen2.generate( System.out );
       
    }
   
}

Man hat mir abgeraten Generics zu verwenden, da diese den Code unlesbarer machen. Was mir aber unter anderem nicht gefällt, dass ich bei Verzicht auf generics die Getter/Setter - Methoden jedes Generators neu für den jeweiligen Parametertyp neu implementiere muss sowie die Definition des Parameters in der Generator-Klasse

Also Beispielsweise folgendes:

Code:
public class WithoutGenerics {

    interface Generator{
        void generate( OutputStream out );
    }
   
   
    static class Generator1 {
        Parameter1 parameter;

        // setze parameter
        void setParameter( Parameter1 parameter){
            this.parameter = parameter;
        }
    }
   
    static class Generator2 {
        Parameter2 parameter;
       
        // und nochmal das ganze
        void setParameter( Parameter2 parameter){
            this.parameter = parameter;
        }
    }
   
    static class Generator3 {
        Parameter3 parameter;
       
        // und nochmal einmal
        void setParameter( Parameter3 parameter){
            this.parameter = parameter;
        }
    }
   
}

Wie werden solche Aufgabenstellungen unter Java gelöst ( komme eigentlich aus der Embeded-Ecke)?

Danke im Voraus!
 
Eigentlich ist das eine reine Vererbungsfrage. Lies dir am Besten mal ein Tutorial zu Thema Vererbung in Java durch.

Letztendlich weiß doch der Parameter am Besten was für zusätzliche Daten noch geschrieben werden müßten. Also kann doch der Parameter das auch tun... Es sei denn es gibt noch andere Dinge die das verhindern.

Java:
static abstract class Parameter{
       
        private final int kennung;         
        pirvate final int size;             
       
        protected Parameter( int kennung, int size ){
            this.kennung = kennung;
            this.size    = size;
        }
        
        public int getSize(){ return this.size;} 
        public int getKennung(){ return this.kennung;}

         abstract void generate(PrintStream data);
    }

Java:
static abstract class Generator{
        private final Parameter parameter;
       
        public void setParameter( Parameter parameter ){
            this.parameter = parameter;
        }
       
        public void generate( OutputStream out ){
            <Generate common parts.....>
            PrintStream data =  new PrintStream(out);

            data.print( parameter.getKennung() );
            data.print( parameter.getSize() );
            
            //Spezielle Daten des Parameters
            parameter.generate(data);
            
            <finish generation>
       }
    }

Java:
    // Spezifischer Parameter 1
static class SystemXYParameter extends Parameter {
       
        // subkennung, gilt nur für parameter des Systems XY
        private final byte subkennung;
       
        // Parametertyp (Gilt nur für SystemXY)
        private final boolean common;
       
        public SystemXYParameter( int kennung, int size, byte subkennung, boolean common ){
            super( kennung, size );
           
            this.subkennung = subkennung;
            this.common = common;
        }

         void generate(PrintStream data){
              data.print( subkennung );
              data.print( common );
         }
    }
 
Man hat mir abgeraten Generics zu verwenden, da diese den Code unlesbarer machen
Also ich finde es ist genau das Gegenteil ist der Fall. Durch den Einsatz von generics wird doch in jedem Statement klar, welche Objekte anliegen.
Durch die Typsicherheit werden einige Flüchtigkeitsfehler bereits zur Kompilierzeit abgefangen. Einige Cast werden überflüssig. Durch z.B. Kovarianz ist der Einsatz auch flexibel genug für komplexere Fachlichkeiten.

Meiner Meinung steigt die Aussagekraft des Codes durch die Verwendung von generics, allerdings auch etwas die Komplexität, was aber für mich zu mehr Lesbarkeit führt.
 
@zeja

ja, das stimmt schon! Leider weiß der Parameter nicht, auf welche weise seine Daten geschrieben werden, deshalb die parametriesierten Generatoren für die einzlnen Parametertypen.

zB.: soll ein Parameter binär geschrieben werden, ein anderes mal wiederum der gleiche Parameter als csv - File!

Code:
   parameter1.setGenerator( new GeneratorXMLParameter1(...) )
   parameter1.generate();
   ....
   ....
   parameter1.setGenerator( new GeneratorBinParameter1(...) );

@TrueSun
bin eigentlich auch der gleichen Meinung, muss mich aber was Java betrifft etwas von C++ umstellen!

Ist die Art, wie ich Generics in meinem Beispielcode einsetze vertretbar unter JAVA oder eher nicht?
 
Zurück