Существует следующая структура приложения:
Реализация метода Id из интерфейса IGetId одинаковая везде. Но, исходя из этой структуры его нужно будет каждый раз переписывать в каждом классе, имплементирующего интерфейсы, порожденные от IGetId.
Если бы не было BaseModel это в принципе не было бы проблемой, т.к. можно было бы вынести реализацию этого метода в какой нибудь абстрактный класс AGetId и от него наследоваться, но множественное наследование не поддерживается, а композиция в данном случае нарушает целостность.
В PHP существует очень удобный инструмент - Trait. Он отлично решает данную проблему, но, к сожалению, в C# такого функционала нету.
В C# есть нечто похожее - extension methods, хоть это и совершенно разные вещи. Я пробовал сделать что-то с использованием методов расширения, но получилось на мой взгляд "не очень":
IGetId
public interface IGetId
{
int Id { get; }
}
Extension methods
public static class CoreExtensions
{
public static int Id(this IGetId obj)
{
return obj.Id;
}
}
В любом случае, это не дало ожидаемого результата, мне по прежнем нужно реализовывать Id в каждом классе.
Существуют ли какие-то средства для решения данной проблемы?
Ответ
Я бы предложил такую иерархию наследования:
// библиотечные интерфейсы
interface IGetId { int Id { get; } }
interface IPerson : IGetId { string Name { get; } }
interface IAddres : IGetId { string City { get; } }
// универсальный базовый класс
class BaseModel { /* ... */ }
// вспомогательный класс
abstract class BaseModelWithId : BaseModel, IGetId
{
int id;
public int Id => id;
}
// реальные классы
class Person : BaseModelWithId, IPerson
{
public string Name { get; set; }
}
Необходимость реализовывать IGetId в Person отпала.
Хотя в общем случае вы правы, trait'ов не хватает. Есть хорошие шансы, что они появятся в будущем C# 8.
Комментариев нет:
Отправить комментарий