Відображення із наслідуванням (шаблон проєктування)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Відображення із наслідуванням (англ. Inheritance Mappers) — шаблон проєктування, який описую структуру класів відображення ієрархії наслідування.

Опис[ред. | ред. код]

При роботі із ієрархією об'єктів, які реалізують наслідування, необхідно зменшити об'єм коду, який використовується для запису і читання зі сховища, а також надати абстрактні та конкретні методи для роботи із даними.

Не зважаючи на те який спосіб наслідування реалізований зі сховищем (або образу декілька) опишемо структуру яка однакова для всіх.

Реалізація[ред. | ред. код]

Нехай дана ієрархія об'єктів.

public class Player
{
    public string Name { get; set; }
}

class Footballer : Player
{
    public string Club { get; set; }
}

class Cricketer : Player
{
    public int BattingAverage { get; set; }
}

Опишемо абстрактний клас для відображення зі структури в пам'яті до доменного об'єкта.

internal class AbstractMapper
{       
    public object Find(int id)
    {
        var row = FindRow(id);
        var domainObject = CreateDomainObject();
        return PopulateDomainObject(row, domainOjbect);
    }

    public void Insert(object domainObject)
    {            
        var dataObject = CreateDataObject();
        var row = PopulateTableObject(domainObject, dataObject);

        db.Insert(row);
    }

    public void Update(object domainObject)
    {
        var id = GetId(domainObject);
        var dataObject = FindRow();
        var row = PopulateTableObject(domainObject, dataObject);

        db.Update(row);
    }

    public void Delete(object domainObject)
    {
        var row = FindRow(id);
        db.Delete(row);
    }

    protected abstract object GetId(object domainObject);
    protected abstract object FindRow(int id);
    protected abstract object CreateDomainObject();
    protected abstract object CreateDataObject();
    protected abstract object PopulateDomainObject(object row, object domainObject);
    protected abstract object PopulateTableObject(object domainObject, object tableObject);
}

Кожний клас ієрархії повинний реалізувати свою логіку відображення.

internal class PlayerMapper : AbstractMapper
{
    protected object FindRow(int id)
    {
        return db.Find(id) as PlayerTable;
    }
    protected object CreateDomainObject(int id)
    {
        return new Player();
    }
    protected object PopulateDomainObject(object row, object domainObject)
    {
        var playerDataRow = row as PlayerTable;
        var playerDomainObject = domainObject as Player;

        playerDomainObject.Name = playerDataRow.Name;

        return playerDomainObject;
    }
         . . .
}

Класи відображення наслідують у тому ж порядку, що і оригінальна ієрархія та при потребі перевикористовують логіку.

internal class FootballerMapper : PlayerMapper
{
    protected override object PopulateDomainObject(object row, object domainObject)
    {
        var footballerDataRow = base.PopulateDomainObject(row, domainObject) as FootballerMapper;

        footballerDataRow.Name = (row as FootballerTable).Club;

        return footballerDataRow;
    }
         . . .
}

Заховаємо вищеописані класи за фасадом, який буде доступний користувачу.

class Mapper
{
    private Dictionary<Type, AbstractMapper> mappers = new Dictionary<Type, AbstractMapper>();

    // метод реєстрації класів відображення
    public void RegisterMapper(Type type, AbstractMapper mapper)
    {
        mappers[type] = mapper;
    }

    private AbstractMapper GetMapper(object domainObject)
    {
        return mappers[domainObject.GetType()];
    }

    public object Find(int id)
    {
        foreach (var mapper in mappers.Values)
        {
            var domainObject = mapper.Find(id);

            if (domainObject != null) return domainObject;
        }
    }

    public void Insert(object domainObject)
    {      
        // делегуємо роботу відповідним класам відображення      
        GetMapper(domainObject).Insert(domainObject);
    }

    public void Update(object domainObject)
    {
        GetMapper(domainObject).Update(domainObject);
    }

    public void Delete(object domainObject)
    {
        GetMapper(domainObject).Delete(domainObject);
    }
}

Див. також[ред. | ред. код]

Джерела[ред. | ред. код]