Question

Je regardais différences entre POCO et DTO (Il semble que sont des années dto avec le comportement de POCO (méthodes)?) et suis tombé sur cet article par Martin Fowler sur le modèle de domaine anémique .

Par manque de compréhension, je crois avoir créé un de ces modèles de domaine anémiques.

Dans l'une de mes applications j'ai mes entités de domaine d'activité définis dans une dll « dpour ». Ils ont beaucoup de propriétés avec son de getter et setter et pas grand-chose. Mon code de logique métier (POPULATE, calculer) est dans une autre dll « bll », et mon code d'accès aux données est dans une dll « dal ». 'Meilleures pratiques' je pensais.

En général, je crée un DTO comme ceci:

dto.BusinessObject bo = new dto.BusinessObject(...)

et le transmettre à la couche de bll comme ceci:

bll.BusinessObject.Populate(bo);

qui, à son tour, exerce une certaine logique et le transmet à la couche de dal comme ceci:

dal.BusinessObject.Populate(bo);

De ma compréhension, de faire de mes DTO dans POCO je dois faire la logique métier et le comportement (méthodes) partie de l'objet. Ainsi, au lieu du code ci-dessus, il est plus comme:

poco.BusinessObject bo = new poco.BusinessObject(...)
bo.Populate();
à savoir

. J'appelle la méthode de l'objet plutôt que de passer l'objet à la méthode.

Ma question est - comment puis-je faire et de conserver encore les « meilleures pratiques » superposition des préoccupations (dll séparée etc ...). Ne pas appeler la méthode sur l'objet signifie que la méthode doit être définie dans l'objet?

S'il vous plaît aider ma confusion.

Était-ce utile?

La solution

En règle générale, vous ne voulez pas introduire la persistance dans vos objets de domaine, car il ne fait pas partie de ce modèle d'affaires (un avion ne se construit pas, il vole passagers / marchandises d'un endroit à un autre). Vous devez utiliser le modèle de référentiel , un

Autres conseils

Je pense que la meilleure façon de clarifier c'est par définition:

DTO: objets de transfert de données:

Ils servent uniquement pour le transport de données généralement entre la couche de présentation et la couche de service. Rien de moins ou plus. En général, il est mis en œuvre en tant que classe et obtient ensembles.

public class ClientDTO
{
    public long Id {get;set;}
    public string Name {get;set;}
}

BO: Business Objects:

Les objets métier représente les éléments d'affaires et naturellement les meilleures pratiques dit qu'ils devraient contenir la logique métier aussi. Comme l'a dit Michael Meadows, il est aussi une bonne pratique d'isoler l'accès aux données à partir de ces objets.

public class Client
{
    private long _id;
    public long Id 
    { 
        get { return _id; }
        protected set { _id = value; } 
    }
    protected Client() { }
    public Client(string name)
    {
        this.Name = name;    
    }
    private string _name;
    public string Name
    {
        get { return _name; }
        set 
        {   // Notice that there is business logic inside (name existence checking)
            // Persistence is isolated through the IClientDAO interface and a factory
            IClientDAO clientDAO = DAOFactory.Instance.Get<IClientDAO>();
            if (clientDAO.ExistsClientByName(value))
            {
                throw new ApplicationException("Another client with same name exists.");
            }
            _name = value;
        }
    }
    public void CheckIfCanBeRemoved()
    {
        // Check if there are sales associated to client
        if ( DAOFactory.Instance.GetDAO<ISaleDAO>().ExistsSalesFor(this) )
        {
            string msg = "Client can not be removed, there are sales associated to him/her.";
            throw new ApplicationException(msg);
        }
    }
}

Service ou classe d'application Ces classes représentent l'interaction entre l'utilisateur et le système et ils utilisent à la fois ClientDTO et le client.

public class ClientRegistration
{
    public void Insert(ClientDTO dto)
    {
        Client client = new Client(dto.Id,dto.Name); /// <-- Business logic inside the constructor
        DAOFactory.Instance.Save(client);        
    }
    public void Modify(ClientDTO dto)
    {
        Client client = DAOFactory.Instance.Get<Client>(dto.Id);
        client.Name = dto.Name;  // <--- Business logic inside the Name property
        DAOFactory.Instance.Save(client);
    }
    public void Remove(ClientDTO dto)
    {
        Client client = DAOFactory.Instance.Get<Client>(dto.Id);
        client.CheckIfCanBeRemoved() // <--- Business logic here
        DAOFactory.Instance.Remove(client);
    }
    public ClientDTO Retrieve(string name)
    {
        Client client = DAOFactory.Instance.Get<IClientDAO>().FindByName(name);
        if (client == null) { throw new ApplicationException("Client not found."); }
        ClientDTO dto = new ClientDTO()
        {
            Id = client.Id,
            Name = client.Name
        }
    }
}

Personnellement, je ne trouve pas les modèles de domaine anémiques si mauvais; Je aime vraiment l'idée d'avoir des objets de domaine qui représentent seulement les données, pas de comportement. Je pense que le principal inconvénient de cette approche est du code de découvrir; vous avez besoin de savoir quelles sont les actions qui sont disponibles pour les utiliser. Une façon de contourner cela et de garder toujours le code de comportement découplé du modèle est d'introduire des interfaces pour le comportement:

interface ISomeDomainObjectBehaviour
{
    SomeDomainObject Get(int Id);
    void Save(SomeDomainObject data);
    void Delete(int Id);
}

class SomeDomainObjectSqlBehaviour : ISomeDomainObjectBehaviour
{
    SomeDomainObject ISomeDomainObjectBehaviour.Get(int Id)
    {
        // code to get object from database
    }

    void ISomeDomainObjectBehaviour.Save(SomeDomainObject data)
    {
        // code to store object in database
    }

    void ISomeDomainObjectBehaviour.Delete(int Id)
    {
        // code to remove object from database
    }
}
class SomeDomainObject
{
    private ISomeDomainObjectBehaviour _behaviour = null;
    public SomeDomainObject(ISomeDomainObjectBehaviour behaviour)
    {

    }

    public int Id { get; set; }
    public string Name { get; set; }
    public int Size { get; set; }


    public void Save()
    {
        if (_behaviour != null)
        {
            _behaviour.Save(this);
        }
    }

    // add methods for getting, deleting, ...

}

De cette façon, vous pouvez garder la mise en œuvre du comportement séparé du modèle. L'utilisation d'implémentations d'interface qui sont injectées dans le modèle fait également le code assez facile à tester, puisque vous pouvez facilement se moquer du comportement.

scroll top