Pregunta

Yo estaba mirando el diferencias entre POCO y DTO (Parece que son de POCO de dto con el comportamiento (métodos?)) y se encontraron con este artículo por Martin Fowler en el modelo de dominio anémico .

A través de la falta de entendimiento, creo que he creado uno de estos modelos de dominio anémicos.

En una de mis aplicaciones que tienen mis entidades del dominio de negocio definidas en un archivo DLL 'dto'. Tienen una gran cantidad de propiedades con captador de la moda y de y no mucho más. Mi código de lógica de negocio (pueblan, calcular) se encuentra en otro DLL 'BLL', y mi código de acceso de datos está en un archivo DLL 'dal'. 'Mejores prácticas' pensé.

Así que normalmente se crea un dto de esta manera:

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

y pasarlo a la capa BLL así:

bll.BusinessObject.Populate(bo);

que a su vez, lleva a cabo alguna lógica y la pasa a la capa dal de este modo:

dal.BusinessObject.Populate(bo);

A mi entender, para hacer mi de dto en POCO de que necesito para hacer la parte de la lógica de negocio y el comportamiento (métodos) del objeto. Así que en lugar del código anterior es más como:

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

ie. Estoy llamando el método en el objeto en lugar de pasar el objeto al método.

Mi pregunta es - ¿cómo puedo hacer esto y todavía mantener la 'mejor práctica' estratificación de las preocupaciones (de DLL separada etc ...). No llamar al método en el objeto significa que el método debe estar definido en el objeto?

Por favor, ayudar a mi confusión.

¿Fue útil?

Solución

Por lo general, usted no quiere introducir la persistencia en sus objetos de dominio, ya que no es parte de ese modelo de negocio (un avión no construye en sí, vuela pasajeros / mercancías de un lugar a otro). Se debe utilizar la patrón de repositorio, un marco ORM , o algún otro esquema de acceso de datos para gestionar el almacenamiento persistente y retreival de un objeto de estado .

Cuando el modelo de dominio anémico entra en juego es cuando estás haciendo cosas como esta:

IAirplaneService service = ...;
Airplane plane = ...;
service.FlyAirplaneToAirport(plane, "IAD");

En este caso, la gestión del estado del avión (si se trata de volar, en donde está, ¿cuál es la hora de salida / aeropuerto, ¿cuál es el tiempo de llegada / aeropuerto, ¿cuál es el plan de vuelo, etc.) se delega a algo externo a la avión ... la instancia AirplaneService.

Una forma de implementar este POCO sería el diseño de la interfaz de esta manera:

Airplane plane = ...;
plane.FlyToAirport("IAD");

Esto es más fácil de encontrar, ya que los desarrolladores saben dónde buscar para hacer volar un avión (justo decir que el avión de hacerlo). También le permite asegurarse de que el estado es solamente de administración interna. A continuación, puede hacer cosas como la ubicación actual de sólo lectura, y asegurarse de que sólo ha cambiado en un solo lugar. Con un objeto de dominio anémica, ya que el estado está impuesta externamente, descubrir dónde se cambia el estado se vuelve cada vez más difícil, ya que la escala de sus aumentos de dominio.

Otros consejos

Creo que la mejor manera de aclarar esto es, por definición:

Dto: Objetos de transferencia de datos:

Sólo sirven para el transporte de datos por lo general entre la capa de presentación y la capa de servicio. Nada menos o más. Por lo general, se implementa como clase con Obtiene y establece.

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

BO: Business Objects:

Los objetos de negocio representa los elementos de negocio y, naturalmente, la mejor práctica dice que deben contener también la lógica de negocio. Según lo dicho por Michael Meadows, también es una buena práctica para aislar el acceso a datos de estos objetos.

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

Servicio o clase de aplicación Estas clases representan la interacción entre el usuario y el sistema y harán uso de ambos ClientDTO y cliente.

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

Personalmente no encuentro esos modelos de dominio anémicos tan malo; Me gusta mucho la idea de tener objetos de dominio que representan sólo datos, no de comportamiento. Creo que el mayor inconveniente de este enfoque es la visibilidad del código; lo que necesita saber qué acciones que están disponibles para utilizarlas. Una manera de conseguir alrededor de eso y aún así mantener el código de conducta desacoplado del modelo es la introducción de interfaces para el comportamiento:

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 esta manera se puede mantener el comportamiento aplicación separada del modelo. El uso de implementaciones de interfaz que se inyecta en el modelo también hace que el código más fácil de probar, ya que se puede burlar fácilmente el comportamiento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top