Sto utilizzando il modello di progettazione del metodo di fabbrica correttamente o quale modello creativo dovrei usare?

3

Ho studiato i modelli di progettazione creativa per la scorsa settimana, perché ho un caso d'uso comune che continua a venire, e non riesco a capire quale modello si adatta al disegno di legge.

Ecco uno scenario semplificato: ho diversi tipi di notifiche, ad es. e-mail, SMS (messaggio di testo), ecc. - e non voglio che il client sappia quale tipo creare o come crearlo, cioè il client non sa nulla delle implementazioni di INotification .

Di seguito è il mio tentativo di approccio "metodo di fabbrica".

internal interface INotification
{
    void Send();
}

public sealed class EmailNotification : INotification
{
    private EmailAddress _sourceAddress;
    private EmailAddress _destAddress;

    public struct EmailAddress
    {
        public string LocalPart { get; set; }
        public string DomainPart { get; set; }

        public EmailAddress(string localPart, string domainPart) : this()
        {
            LocalPart = localPart;
            DomainPart = domainPart;
        }
    }

    internal EmailNotification(EmailAddress sourceAddress, EmailAddress destAddress)
    {
        _sourceAddress = sourceAddress;
        _destAddress = destAddress;
    }

    void INotification.Send()
    {
        // send via email technology
        throw new NotImplementedException();
    }
}

public sealed class SmsNotification : INotification
{
    private PhoneNumber _sourceNumber;
    private PhoneNumber _destNumber;

    public struct PhoneNumber
    {
        public ushort CountryCode { get; set; }
        public ushort AreaCode { get; set; }
        public ushort ExchangeCode { get; set; }
        public ushort LineNumber { get; set; }

        public PhoneNumber(ushort countryCode, 
                           ushort areaCode, 
                           ushort exchangeCode, 
                           ushort lineNumber) : this()
        {
            CountryCode = countryCode;
            AreaCode = areaCode;
            exchangeCode = ExchangeCode;
            LineNumber = lineNumber;
        }
    }

    internal SmsNotification(PhoneNumber sourceNumber, PhoneNumber destNumber)
    {
        _sourceNumber = sourceNumber;
        _destNumber = destNumber;
    }

    void INotification.Send()
    {
        // send via SMS tecnology
        throw new NotImplementedException();
    }
}

internal class NotificationFactory
{
    internal INotification CreateSmsNotification(
                                 SmsNotification.PhoneNumber sourceNumber, 
                                 SmsNotification.PhoneNumber destNumber)
    {
        return new SmsNotification(sourceNumber, destNumber);
    }

    internal INotification CreateEmailNotification(
                                 EmailNotification.EmailAddress sourceAddress, 
                                 EmailNotification.EmailAddress destAddress)
    {
        return new EmailNotification(sourceAddress, destAddress);
    }
}

Lo userei dal client in questo modo:

var factory = new NotificationFactory();

var notification = factory.CreateEmailNotification(
    new EmailNotification.EmailAddress("myname", "nothing.com"), 
    new EmailNotification.EmailAddress("yourname", "nothing.com"));

notification.Send();

Ora, so che un approccio al metodo factory dovrebbe coinvolgere solo un metodo che richiede, ad es., un'enumerazione per determinare il tipo dell'oggetto restituito. Non ho visto alcun riferimento che utilizza l'approccio di cui sopra in cui esistono più metodi specializzati. Sto chiamando lo schema sbagliato? Lo sto facendo nel modo sbagliato (cioè dovrei usare un modello diverso)?

Ho anche preso in considerazione l'utilizzo di un'iniezione di dipendenza con un contenitore DI, ma la mia comprensione è che il modello semplifica i test ed è un'alternativa (o riorganizzazione) dei vari modelli di progettazione di fabbrica. In definitiva, avrei lo stesso problema, credo, nel mio contenitore DI che sta cercando di capire come prendere input complessi e decidere quale sottoclasse produrre.

Forse ho bisogno di una combinazione di fabbrica e costruttore. So che un builder è usato per produrre un singolo tipo (in contrasto con una factory che emette un determinato tipo derivato o implementazione dell'interfaccia), ma il fatto che io abbia più metodi coinvolti per creare determinate istanze specializzate sembra più un costruttore. p>

Qualsiasi aiuto sarebbe molto apprezzato.

    
posta rory.ap 24.03.2016 - 17:04
fonte

1 risposta

3

Hai fatto un buon lavoro di astrazione della notifica, ma non hai applicato un'astrazione simile al lavoro di creazione del target di notifica.

Quello che stai facendo non è un "Metodo di Fabbrica", perché, come stai osservando, non usa un singolo metodo che decide, di solito con i parametri forniti, quale vera classe creare. Nel tuo codice, il cliente sceglie direttamente tra i metodi; mentre nel modello di metodo di fabbrica, il cliente immediato non dovrebbe realmente conoscere o preoccuparsi.

Né si tratta di una "Fabbrica astratta" perché anche il cliente non dovrebbe sapere o preoccuparsi. In questo senso, lo schema di fabbrica astratto si basa sul modello di metodo di fabbrica.

Il codice non è nemmeno un modello di builder, perché NotificationFactory crea immediatamente un'istanza dell'oggetto senza ulteriori indugi.

Inoltre, al tuo cliente è richiesto di usare new nel richiamare NotificationFactory , che ha un po 'di odore: lo stai chiamando come fabbrica, ma il cliente deve effettivamente usare new (per creare i parametri), che è ciò che la fabbrica è progettata per ovviare. L'idea della fabbrica è quella di creare un accoppiamento lento tra l'utente della fabbrica e ciò che viene creato. A causa dello specifico new utilizzato per i parametri, questo rende l'accoppiamento stretto.

Quello che ti suggerisco è di analizzare il tuo caso d'uso e vedere se c'è bisogno di una fabbrica. In caso contrario, torna semplicemente a utilizzare new direttamente.

Quando è necessario separare la responsabilità per la scelta del metodo di notifica dalla creazione dell'istanza, è necessario introdurre uno stabilimento.

    
risposta data 24.03.2016 - 18:13
fonte