POCO's, DTO, и анемичные модели предметной области DLL

Как отмечали другие ответы, использование массивов ячеек , вероятно, является наиболее простым подходом, который приведет к тому, что ваша переменная name будет массивом ячеек, где каждый элемент ячейки содержит строку.

Однако есть еще одна опция, использующая функцию STRVCAT , которая будет вертикально объединять строки. Вместо создания массива ячеек будет создана двумерная матрица символов, в которой каждая строка содержит одну строку. STRVCAT автоматически дополняет концы строк пробелами, если необходимо правильно заполнить строки матрицы:

>> string1 = 'hi';
>> string2 = 'there';
>> S = strvcat(string1,string2)

S =

hi
there

20
задан Community 23 May 2017 в 12:25
поделиться

3 ответа

Как правило, вы не хотите вводить персистентность в свои объекты домена, поскольку это не является частью этой бизнес-модели (самолет не строит себя, он перевозит пассажиров / грузы из одного места другому). Вы должны использовать шаблон репозитория , ORM framework или какой-либо другой шаблон доступа к данным для управления постоянным хранением и повторным воспроизведением состояния объекта .

Модель анемичной области вступает в игру, когда вы делаете что-то вроде этого:

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

В данном случае управление состоянием самолета (летит ли он, где он находится, какое время вылета / аэропорт, что время прибытия / аэропорт, план полета и т. д.) делегируется чему-то внешнему по отношению к самолету ... экземпляру AirplaneService.

POCO-способ реализации этого мог бы заключаться в разработке вашего интерфейса следующим образом:

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

Это более обнаружимо, поскольку разработчики знают, где искать, чтобы самолет полетел (просто скажите самолету сделать это). Это также позволяет гарантировать, что состояние только управляется внутренне. Затем вы можете сделать такие вещи, как текущее местоположение, только для чтения и гарантировать, что оно изменено только в одном месте. В случае анемичного объекта домена, поскольку состояние устанавливается извне, обнаружение места изменения состояния становится все труднее по мере увеличения масштаба вашего домена.

Это также позволяет гарантировать, что состояние только управляется внутренне. Затем вы можете сделать такие вещи, как текущее местоположение, только для чтения и гарантировать, что оно изменено только в одном месте. В случае анемичного объекта домена, поскольку состояние устанавливается извне, обнаружение места изменения состояния становится все труднее по мере увеличения масштаба вашего домена.

Это также позволяет гарантировать, что состояние только управляется внутренне. Затем вы можете сделать такие вещи, как текущее местоположение, только для чтения и гарантировать, что оно изменено только в одном месте. В случае анемичного объекта домена, поскольку состояние устанавливается извне, обнаружение места изменения состояния становится все труднее по мере увеличения масштаба вашего домена.

22
ответ дан 30 November 2019 в 00:01
поделиться

Лично я не считаю эти модели анемической области такими уж плохими; Мне очень нравится идея иметь объекты домена, которые представляют только данные, а не поведение. Я думаю, что основным недостатком этого подхода является возможность обнаружения кода; вам нужно знать, какие действия доступны для их использования. Один из способов обойти это и по-прежнему отделить код поведения от модели - ввести интерфейсы для поведения:

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

}

Таким образом вы можете отделить реализацию поведения от модели. Использование реализаций интерфейса, которые вводятся в модель, также упрощает тестирование кода, поскольку вы можете легко имитировать поведение.

6
ответ дан 30 November 2019 в 00:01
поделиться

Я думаю, что лучший способ уточнить это по определению:

DTO: Объекты передачи данных:

Они служат только для передачи данных, как правило, между уровнем представления и уровнем сервиса. Ни меньше, ни больше. Обычно это реализуется как класс с получением и набором.

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

BO: Business Objects:

Бизнес-объекты представляют собой бизнес-элементы, и, естественно, лучшие практики говорят, что они также должны содержать бизнес-логику. Как сказал Майкл Медоуз, также рекомендуется изолировать доступ к данным от этих объектов.

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

Класс службы или приложения Эти классы представляют взаимодействие между пользователем и системой, и они будут использовать как ClientDTO, так и 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
        }
    }
}
10
ответ дан 30 November 2019 в 00:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: