Il modello di strategia può essere sovrautilizzato?

4

Esempio: un file, che rappresenta una versione serializzata di un oggetto, deve essere letto e deserializzato. Sarebbe semplice implementarlo se ci interessa solo un singolo formato di serializzazione, ma esistono molti di questi formati (JSON, YAML, ecc.).

Un modo per gestirlo sarebbe creare un tipo / interfaccia serializzatore astratto con metodi come deserializeToArray , deserializeToObject e così via, e passare questa interfaccia come dipendenza al fine di scindere qualsiasi classe dipendente da qualsiasi implementazione concreta.

Questo potrebbe essere ulteriormente generalizzato avendo i metodi di serializzazione effettivamente implementazioni di un'altra interfaccia, che chiameremo Transform . Quindi, stiamo usando di nuovo il modello di strategia, questa volta incapsulando una famiglia di algoritmi per trasformare un tipo di dati in un altro oggetto o formato di array desiderato.

Questo è forse un uso eccessivo del modello di strategia? Ci sono modi migliori per strutturare le cose qui o modelli più adatti a questo tipo di problema? Ci sono degli svantaggi nell'usare diversi schemi strategici annidati come in questo esempio?

    
posta ubtng 10.07.2011 - 03:55
fonte

4 risposte

4

Ciò di cui stai parlando è la programmazione di astrazioni, che non implica il modello di strategia.

Programmare astrazioni è sempre una buona pratica. Non ci sono praticamente ulteriori sforzi per fornire un'interfaccia o una classe base astratta per un'implementazione concreta, e molti strumenti di refactoring ora possono farlo automaticamente per te.

Come astratto per renderlo è una domanda diversa.

Nel tuo primo esempio, hai semplicemente un tipo astratto. Puoi programmare tutto per utilizzare un generico Serializer o ISerializer e quindi cablare una singola implementazione predefinita in un contenitore IoC come Castle o Spring. Semplice. Fatto.

Nella seconda istanza, però, stai progettando una funzionalità astratta. Stai provando a prevedere come potrebbe essere usato questo tipo astratto in futuro, e probabilmente starai sbagliando. Qui si applica il principio YAGNI ; a meno che tu non abbia qualche motivo per credere che la tua applicazione abbia una vera e propria interfaccia di "trasformazione" che può trasformare qualsiasi cosa in qualcos'altro, e a meno che tu non abbia individuato i requisiti per questo, quindi stai sprecando il tuo tempo per programmarlo. Forse dovresti semplicemente utilizzare una delle tante lingue di trasformazione XML esistenti se hai bisogno di quel tipo di flessibilità.

Niente di tutto ciò ha davvero a che fare con il modello di strategia. Il modello della strategia significa che non solo stai codificando contro un tipo astratto, ma che sei che scegli quale tipo concreto utilizzare in base a informazioni conosciute solo al runtime . Questo non è né esplicito né implicito nella tua domanda.

Se hai solo un'implementazione, l'implementazione di un modello di strategia è un assolutamente eccessivo, a meno che tu non sappia per certo che dovrai supportare strategie aggiuntive quasi subito dopo.

Ma questo non ti preclude l'utilizzo di tipi astratti. Questo è generalmente il modo in cui la maggior parte delle applicazioni OO sono progettate ora, utilizzando l'integrazione delle dipendenze per il codice e un contenitore IoC per la configurazione. Direi che questo è più produttivo della codifica per tipi concreti, perché (a) è molto più semplice testare e simulare, e (b) codificare rapidamente un'interfaccia ti permette di continuare il tuo compito attuale senza molta distrazione, invece di andare fuori e scrivere una classe completamente nuova perché non puoi continuare senza di essa.

Quindi usa decisamente i tipi astratti, ma non pensare troppo alle cose e dedica molto tempo a occuparsi di come generalizzarle. È più facile refactoring più tardi di quanto non funzioni con un'interfaccia gonfia.

    
risposta data 10.07.2011 - 17:05
fonte
5

L'uso eccessivo di schemi di progettazione è di per sé un anti-modello. D'altra parte, YAGNI non può essere abusato. Chiediti se hai bisogno di supportare sia XML che JSON oggi? In caso contrario, implementare un modello per questo chiaramente un uso eccessivo.

Punto di apprendimento: crea solo (o ridefinisci) le astrazioni quando ne hai effettivamente bisogno.

    
risposta data 10.07.2011 - 17:09
fonte
2

Nessun modello è necessario, IMO. Resta semplice in questo caso. In Python:

# You may add or delete supported formats as needed.
format2serial = {'XML' : serialXml, 'JSON' : serialJSON, 'YAML' : serialYaml}
format2deserial = {'XML' : deserialXml, 'JSON' : deserialJSON, 'YAML' : deserialYaml}

def serialize(obj, format):
    try:
        serializer = format2serial(format.upper())
        serializer(obj)
    except:
        raise Exception('Unsupported serialization format: {0}.'.format(format))

def deserialize(obj, format):
    try:
        deserializer = format2deserial(format.upper())
        return deserializer(obj)
    except:
        raise Exception('Unsupported de-serialization format: {0}.'.format(format))

# You may add or delete supported [de]serializers as needed.
def serialJSON(obj): ...
def serialYaml(obj): ...
def serialXml(obj): ...

def deserialJSON(obj): ...
def deserialYaml(obj): ...
def deserialXml(obj): ...
    
risposta data 10.07.2011 - 17:11
fonte
1

Penso che un fattore da tenere in considerazione quando si parla dell'uso intenso dei modelli sia il progetto e / o le dimensioni dell'applicazione. Diciamo che il nostro progetto consiste di 10 squadre ogni 5-6 membri, quindi sì, implementare tutti i tipi di schemi fin dall'inizio può essere una buona idea.

Se il progetto inizia in piccolo e non sai come si evolverà, ti consiglio di preparare per determinati modelli. Per esempio. puoi facilmente preparare il modello di strategia usando il modello di metodo di fabbrica :

Serializer s = SerializerFactory.getSerializer("JSON");
s.serialize(someObject);

Una prima implementazione della factory potrebbe essere simile a questa:

public class SerializerFactory {

    public static Serializer getSerializer(String protocol) {
          return new DefaultSerializer(protocol);
    }
}

E DefaultSerializer:

public class DefaultSerializer implements Serializer {
    private String protocol = null;

    public DefaultSerializer(String protocol) {
          this.protocol = protocol;
    }

    public void serialize(Object someObject) {
          if ("JSON".equals(this.protocol)) {
               // your logic here.
          } else if ("SOAP".equals(this.protocol)) {
               // your logic here.
          }...
    }

}

Questo ti porta nella posizione di "facilmente" implementare il Pattern Strategia in un secondo momento toccando solo la fabbrica e il DefaultSerializer ... il mio 2 cent

    
risposta data 10.07.2011 - 13:47
fonte