Frage

Ich war auf der Suche auf der Seite Unterschiede zwischen POCO und DTO (es, dass POCO erscheint DTO ist mit dem Verhalten (Methoden?)) und kam über diesem Artikel von Martin Fowler auf dem anämischen Domänenmodell .

Durch Mangel an Verständnis, ich glaube, ich eine dieser anämischen Domänenmodelle erstellt haben.

In einem meiner Anwendungen habe ich meine Business-Bereich definiert Entitäten in einer ‚dto‘ dll. Sie haben eine Menge von Eigenschaften mit Getter und Setter ist das und sonst nicht viel. Mein Business-Logik-Code (bevölkert, berechnet) ist in einem anderen 'bll' dll, und mein Datenzugriffscode ist in einem 'dal' dll. 'Best practice', dachte ich.

So typischerweise erstelle ich eine dto etwa so:

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

und gibt es an die BLL Schicht etwa so:

bll.BusinessObject.Populate(bo);

, die wiederum eine gewisse Logik führt und leitet sie an die dal Schicht etwa so:

dal.BusinessObject.Populate(bo);

Von meinem Verständnis meiner DTO in POCO zu machen Ich brauche den Business-Logik und Verhalten (Methoden) Teil des Objekts zu machen. Anstatt also den Code oben ist es eher wie:

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

dh. Ich bin die Methode für das Objekt aufrufen, anstatt das Objekt an die Methode übergeben.

Meine Frage ist - wie kann ich dies tun und immer noch die ‚best practice‘ Schichtung von Bedenken (getrennte DLL etc ...) behalten. Nicht den Aufruf der Methode für das Objekt bedeuten, dass die Methode muss in dem Objekt definiert werden?

Bitte helfen Sie meine Verwirrung.

War es hilfreich?

Lösung

Normalerweise wollen Sie nicht Persistenz in Ihre Domain-Objekte einzuführen, da sie nicht Teil dieses Geschäftsmodell ist (ein Flugzeug konstruieren nicht selbst, er fliegt Passagiere / Fracht von einem Ort zum anderen). Sie sollten die Repository-Muster verwenden, ein

Andere Tipps

Ich denke, der beste Weg, dies per Definition zu klären ist:

DTO: Datenübertragung Objekte:

Sie nur für Datentransport dienen in der Regel zwischen Präsentationsschicht und Service-Schicht. Nichts weniger oder mehr. Im allgemeinen wird es als Klasse implementiert mit bekommt und setzt.

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

BO: Business Objects:

Business-Objekte stellen die betriebswirtschaftlichen Elemente und natürlich die beste Praxis, sagt sie auch Business-Logik enthalten soll. Wie gesagt von Michael Meadows, es ist auch ein gute Praxis Datenzugriff von diesen Objekten zu isolieren.

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 oder Anwendungsklasse Diese Klassen stellen die Interaktion zwischen Benutzer und dem System, und sie werden der Einsatz von sowohl ClientDTO und Kunden machen.

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
        }
    }
}

Persönlich finde ich nicht jene Anemic Domain Model so schlecht; Ich mag die Idee von Domänenobjekten aufweist, die nur Daten darstellen, nicht Verhalten. Ich denke, der größte Nachteil bei diesem Ansatz Auffindbarkeit des Codes ist; Sie müssen wissen, welche Aktionen, die sie zur Verfügung stehen zu können. Ein Weg, um das zu bekommen und immer noch das Verhalten Code hält vom Modell entkoppelt ist Schnittstellen für das Verhalten vor:

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, ...

}

Auf diese Weise können Sie das Verhalten Umsetzung vom Modell getrennt halten. Die Verwendung von Interface-Implementierungen, die in das Modell eingespritzt werden, macht auch der Code recht einfach zu testen, da Sie leicht das Verhalten spotten können.

scroll top