Utilizzo di un DTO superset per un numero di metodi in una classe

3

Considera una classe con un numero di metodi che sono richiesti per restituire un numero di valori ciascuno. In un linguaggio strongmente tipizzato come C #, possiamo avere l'effetto di restituire più quel valore da un metodo utilizzando DTO classi.

Considera che i valori che i miei metodi devono restituire collettivamente sono questi (chiamiamolo pool ):

A, B, C, D, E

Ma non tutti i metodi sono necessari per restituire tutti . Ad esempio, considera quanto segue:

Method      Values to return:
==============================
Method1     A, B, C
Method2     A, E
Method3     B, D, E
Method4     D, E
Method5     A, C, D, E

Si ottiene l'idea, i valori da restituire sono un assortimento di valori dal pool .

Questo codice dovrebbe aiutarlo a chiarire la situazione. Sto usando C # qui.

namespace TestBed
{
    public interface MyInterface
    {
        MyDTO Method1(/* parameters */);
        MyDTO Method2(/* parameters */);
        // definitions for Method3() and so on
    }

    // Writing the DTO class here, as it is specific only to the class
    // that implements this interface
    public class MyDTO
    {
        public string A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
        public string D { get; set; }
        public string E { get; set; }

        // possibly a constructor
    }
}

Una classe che implementa l'interfaccia:

public class MyClass : MyInterface
{
    public MyDTO Method1(/* parameters */)
    {
        MyDTO dto = new MyDTO();
        // populate the properties of dto specific to this method
        dto.A = "some values for A";
        dto.B = "some values for B";
        dto.C = "some values for C";

        return dto;
    }

    public MyDTO Method2(/* parameters */)
    {
        MyDTO dto = new MyDTO();
        // populate the properties of dto specific to this method
        dto.A = "some values for A";
        dto.E = "some values for E";

        return dto;
    }

    // similar code for the other methods
}

Come puoi vedere, un metodo dice che Method1() popola solo le proprietà del dto ad esso pertinenti, ad es. A , B e C per Method1() . Le mie preoccupazioni sono:

  • Sebbene un metodo compili solo le proprietà ad esso relative, il destinatario di questo metodo può accedere anche ad altri valori del DTO, ad es. le proprietà D e E per Method1() .
  • Un metodo che popola solo pochi numeri di valori del DTO (solo 2 per Method4() ), restituisce comunque un oggetto con molti altri valori che non sono utili per questo metodo. Sembra un sovraccarico non necessario.

Riguardo alle preoccupazioni di cui sopra, perché (o perché no, forse) dovrei usare un DTO in questi casi? Esiste un approccio alternativo migliore in questo scenario, almeno fino a quando C # 7 è intorno .

    
posta Sнаđошƒаӽ 16.10.2016 - 19:24
fonte

2 risposte

1

Restituisce una collezione di KeyValuePair<K,V> con solo i valori per il particolare metodo chiamato.

o

Restituisce un particolare tipo Tuple per un dato MethodX .

o

Imposta i valori che non stai inviando. Questo potrebbe essere un problema: come fai a capire la differenza tra "ignora me" e il suo valore È quello predefinito.

o

parametrizza il metodo per dire quali valori sono desiderati. Il tipo / struttura di ritorno spetta a te.

o

Dai al cliente l'onere di ignorare le cose giuste. Nel qual caso vedo una proliferazione di classi "DTO" più anemiche dal lato del cliente.

Dai al cliente qualcosa con cui possono effettivamente lavorare

Qualunque sia l'implementazione, dovrebbe essere nella classe DTO stessa. Pertanto, il DTO non è più un DTO di per sé, ma una classe "reale" come dovrebbe essere. Come bonus puoi dimenticare tutto quel interface di spese generali.

    
risposta data 16.10.2016 - 21:06
fonte
1

Non sono sicuro di quanto senso possa avere, ma, FWIW:

(forzato)

/// <summary>
/// TDto below not meant to be closed over the actual DTOs, but only
/// local proxies of those that a (likewise) proxy implementation of
/// the interface will reflect over/interpret (cf. System.Reflection)
/// before forwarding the call to the actual service client,
/// with the actual DTOs
/// </summary>
public interface IMyBusinessFacade
{
    TDto GetById<TDto, TIdentifier>(TDto protoDto, TIdentifier id)
        // DTOs being anemic by their very nature, whatever will be TDto on call sites (as a closed type)
        // we can reasonably expect it to come as either (a) a named reference type
        // (most likely with a public parameter-less constructor) or
        // (b) an anonymous type that a proxy can validate (or not) before even bothering
        // to forwarding to the service layer
        where TDto : class;

    IEnumerable<TDto> GetFiltered<TDto, TCriteria>(TDto protoDto, TCriteria criteria)
        where TDto : class;
}

// If the tooling can generate service clients, it might as well generate
// such local proxies for those clients
public class MyBusinessFacade : /*ProxyBase, */IMyBusinessFacade
{
    private IMyBusinessService service;

    public MyBusinessFacade(IMyBusinessService service)
    {
        this.service = service;
    }

    public TDto GetById<TDto, TIdentifier>(TDto protoDto, TIdentifier id)
        where TDto : class
    {
        // auto-generated implementation to use reflection over typeof(TDto)
        // and typeof(TIdentifier) before forwarding the calls to the service layer
        // if applicable (or throw exception on invalid client-specified input)
        // ...
        // resolve, using this.service
        // ...
        // instantiate and hydrate a TDto, if applicable
        TDto dto = ...
        // and return it
        return dto;
    }

    public IEnumerable<TDto> GetFiltered<TDto, TCriteria>(TDto protoDto, TCriteria criteria)
         where TDto : class
    {
        // ...
        // resolve, using this.service
        // ...
        // instantiate and hydrate an IEnumerable<TDto>, if applicable
        IEnumerable<TDto> dtos = ...
        // and return it
        return dtos;
    }
}

public enum CustomerKind
{
    Regular,
    Premium
}

public enum SubscriptionType
{
    OneMonthTrial,
    MonthlyAutoRenew
}

Quindi, più avanti:

        // (actual service client)
        IMyBusinessService myService = ...
        // ...
        IMyBusinessFacade myFacade = new MyBusinessFacade(myService);

        var GetCustomerById =
            new
            {
                // the facade/proxy will relate/interpret this property's
                // type & name (but not its useless value) with that of the id parameter
                CustomerId = default(int),

                // facade/proxy to interpret those too, as what the caller
                // expects:
                CustomerKind = default(CustomerKind),
                // etc
            };

        var GetCustomerContractById =
            new
            {
                ContractId = default(int),

                // facade/proxy to interpret those too, as what the caller
                // expects:
                Customer = GetCustomerById,
                SubscriptionType = default(SubscriptionType),
                // etc
            };

        var customer123 = myFacade.
            GetById
            (
                GetCustomerById,
                123
            );

        var contrat456 = myFacade.
            GetById
            (
                GetCustomerContractById,
                456
            );

        Console.WriteLine("Customer: {0}, {1} ...", customer123.CustomerId, customer123.CustomerKind);
        Console.WriteLine("Contract: {0} (Customer: {1}) Subscription: {2} ...", contrat456.ContractId, contract456.Customer.CustomerId, contract456.SubscriptionType);

Concesso, un uso piuttosto hacker del tipo di inferenza di C # combinata con tipi anonimi, anche se non di nuovo, in realtà, come è quello che, ad esempio, alcuni serializzatori JSON già fanno, per comodità del chiamante, come per esempio:

di JSON.NET Deserializza un tipo anonimo

'Spero che questo aiuti.

    
risposta data 23.10.2016 - 06:32
fonte

Leggi altre domande sui tag