Design pattern consigliato per gestire più algoritmi di compressione per una gerarchia di classi

3

Per tutti voi esperti OOD. Quale sarebbe il modo consigliato per modellare il seguente scenario?

Ho una certa gerarchia di classi simile alla seguente:

class Base {
   ...
}

class Derived1 : Base {
   ...
}

class Derived2 : Base {
   ...
}
...

Successivamente, vorrei implementare diversi motori di compressione / decompressione per questa gerarchia. (Ho già il codice per diverse strategie che gestiscono i casi più diversi, come la compressione dei file, la compressione del flusso di rete, la compressione del sistema legacy, ecc.)

Vorrei che la strategia di compressione fosse inseribile e scelta al momento dell'esecuzione, tuttavia non sono sicuro di come gestire la gerarchia delle classi. Attualmente ho un design con accoppiamento stretto simile a questo:

interface ICompressor {
   byte[] Compress(Base instance);
}

class Strategy1Compressor : ICompressor {
   byte[] Compress(Base instance) {

      // Common compression guts for Base class
      ...
      //

      if( instance is Derived1 ) {
         // Compression guts for Derived1 class 
      }
      if( instance is Derived2 ) {
         // Compression guts for Derived2 class
      }

      // Additional compression logic to handle other class derivations
      ...
   }

}

Così com'è, ogni volta che aggiungo una nuova classe derivata ereditata da Base, dovrei modificare tutte le strategie di compressione per tenere conto di questa nuova classe. Esiste un modello di progettazione che mi consente di disaccoppiarlo e mi consente di introdurre facilmente più classi nella gerarchia di base e / o in altre strategie di compressione?

    
posta sgorozco 25.06.2013 - 21:19
fonte

3 risposte

3

Pattern visitatori :

Notacheilcodicenoncontieneif-then-elseoswitch-casestruttureperselezionareilcompressoreappropriato.Nonènecessariodalmomentocheipatternvisitatoriconsentonolaspedizioneappropriata.

publicinterfaceIBase{voidaccept(ICompressorVisitore);voidsetName(Strings);StringgetName();}publicclassBase1implementsIBase{privateStringname="";
    @Override
    public void accept(ICompressorVisitor e) {
        e.visit(this);      
    }

    @Override
    public void setName(String s) {
        this.name = s;      
    }

    @Override
    public String getName() {
        return "Base1("+this.name+")";
    }

}

public class Base2 implements IBase  {
    private String name="";
    @Override
    public void accept(ICompressorVisitor e) {
        e.visit(this);      
    }

    @Override
    public void setName(String s) {
        this.name = s;      
    }

    @Override
    public String getName() {
        return "Base2("+this.name+")";
    }
}

public interface ICompressorVisitor {
    void visit(Base1 base);
    void visit(Base2 base);
}

public class CompressorX implements ICompressorVisitor {

    @Override
    public void visit(Base1 base) {
        System.out.println("Compressing "+base.getName()+" using algorithm X optimized for Base1");

    }

    @Override
    public void visit(Base2 base) {
        System.out.println("Compressing "+base.getName()+" using algorithm X optimized for Base2");
    }

}

public class CompressorY implements ICompressorVisitor {

    @Override
    public void visit(Base1 base) {
        System.out.println("Compressing "+base.getName()+" using algorithm Y optimized for Base1");

    }

    @Override
    public void visit(Base2 base) {
        System.out.println("Compressing "+base.getName()+" using algorithm Y optimized for Base2");

    }

}

public class Test {

    public static void main(String[] args) {
        Base1 b1 = new Base1();
        b1.setName("a");
        Base2 b2 = new Base2();
        b2.setName("b");

        CompressorX x = new CompressorX();
        CompressorY y = new CompressorY();

        b1.accept(x);
        b1.accept(y);

        b2.accept(x);
        b2.accept(y);

    }

}

Output del test:

Compresing Base1(a) using algorithm X optimized for Base1
Compresing Base1(a) using algorithm Y optimized for Base1
Compresing Base2(b) using algorithm X optimized for Base2
Compresing Base2(b) using algorithm Y optimized for Base2
    
risposta data 25.06.2013 - 23:02
fonte
1

Supponendo che ogni combinazione di Derived e strategia di compressione comprima in modo diverso, allora non è possibile separarli. Puoi rifattorizzare il link in qualche modo per evitare le dichiarazioni switch e if/else , ma non puoi rimuoverlo interamente - ognuno dovrà essere a conoscenza degli altri.

Se è possibile separare l'algoritmo di compressione dalla conoscenza di ciò che sta comprimendo, è possibile memorizzare un ICompressor da qualche parte e quindi popolarlo in fase di runtime. ICompressor dovrebbe operare su un tipo standard e ogni Derived dovrebbe essere in grado di convertire in quel tipo (probabilmente tramite chiamata di funzione come .Compress(this.PrepForCompression()) o .Compress(this.Serialize()) ).

    
risposta data 25.06.2013 - 23:36
fonte
-2

Puoi provare una combinazione di strategia e fabbrica:

public abstract class Compressor {
    private Base base;

    public Compressor(BaseType baseType) {//BaseType can be an enum
        if (baseType == DERIVED1) {
            base = new Derived1();
        } else if (baseType == DERIVED2) {
            base = new Derived2();
        }
    }

    protected Base GetBase() {
        return base;
    }

    public abstract byte[] Compress();
}

public class Strategy1Compressor : ICompressor {
    public byte[] Compress() {
        Base base = super.GetBase();//hope this is legal in C#
        //do compression logic based on base
    }
}

Puoi anche fornire una fabbrica sui compressori:

public class CompressorFactory {
    public static Compressor CreateCompressor(CompressorType compressorType, 
                                              BaseType baseType) {
        if (compressorType == STRATEGY1_COMPRESSOR) {//again enum
            return new Strategy1Compressor(baseType);
        } else if //...
    }    
}

Nota: spero che il codice sopra sia un codice C # legale, in quanto ho familiarità con Java.

    
risposta data 25.06.2013 - 22:34
fonte

Leggi altre domande sui tag