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.