У меня есть класс: A
это состав из нескольких меньших классов B
, C
и D
.
B
, C
И D
реализовывать интерфейсы IB
, IC
и ID
соответственно.
Так как A
поддерживает все функциональные возможности B
, C
и D
, A
реализует IB
, IC
и ID
также, но это, к сожалению, приводит к большой перенаправления в реализацииA
Вот так:
interface IB
{
int Foo {get;}
}
public class B : IB
{
public int Foo {get {return 5;}}
}
interface IC
{
void Bar();
}
public class C : IC
{
public void Bar()
{
}
}
interface ID
{
string Bash{get; set;}
}
public class D: ID
{
public string Bash {get;set;}
}
class A : IB, IC, ID
{
private B b = new B();
private C c = new C();
private D d = new D();
public int Foo {get {return b.Foo}}
public A(string bash)
{
Bash = bash;
}
public void Bar()
{
c.Bar();
}
public string Bash
{
get {return d.Bash;}
set {d.Bash = value;}
}
}
Есть ли способ избавиться от какого-либо перенаправления в этом шаблоне A
? B
, C
И D
все реализовать разные , но общие функциональные возможности , и мне нравится , что A
орудия IB
, IC
и ID
потому , что это означает , что я могу передать в A
себя как зависимость сопоставления этих интерфейсов, и не должен подвергать внутренние вспомогательные методы.
A
реализоватьIB
,IC
иID
он чувствует себя более разумно писатьPerson.Walk()
в противоположностьPerson.WalkHelper.Walk()
, например.Ответы:
То, что вы ищете, обычно называют миксином . К сожалению, C # изначально не поддерживает их.
Есть несколько обходных путей: один , два , три и многие другие.
Мне действительно очень нравится последний. Идея использования автоматически сгенерированного частичного класса для генерации шаблона, вероятно, наиболее близка к действительно хорошему решению:
источник
Хотя Visual Studio 2015 и не сокращает шаблон в самом коде, теперь в нем есть опция рефакторинга, которая автоматически генерирует шаблон для вас.
Чтобы использовать это, сначала создайте свой интерфейс
IExample
и реализациюExample
. Затем создайте свой новый классComposite
и сделайте его наследуемымIExample
, но не реализуйте интерфейс.Добавьте свойство или поле типа
Example
к своемуComposite
классу, откройте меню быстрых действий для токенаIExample
вComposite
файле класса и выберите «Реализовать интерфейс через« Пример »», где «Пример» в этом случае является именем поля или свойства.Следует отметить, что хотя Visual Studio будет генерировать и перенаправлять все методы и свойства, определенные в интерфейсе, для этого вспомогательного класса, она не будет перенаправлять события с момента публикации этого ответа.
источник
Ваш класс делает слишком много, поэтому вы должны реализовать так много шаблонов. Вы говорите в комментариях:
Я не согласен. Ходьба, вероятно, включает много правил и не принадлежит
Person
классу - он принадлежитWalkingService
классу сwalk(IWalkable)
методом, который реализует PersonIWalkable
.Всегда имейте в виду принципы SOLID при написании кода. Двумя, которые наиболее применимы здесь, являются разделение проблем (извлечение кода ходьбы в отдельный класс) и разделение интерфейса (разделение интерфейсов на конкретные задачи / функции / возможности). Звучит так, как будто у вас могут быть некоторые из I с несколькими интерфейсами, но затем вы отменяете всю свою хорошую работу, заставляя один класс реализовать их.
источник
walk(IWalkable)
метода, мне лично это не нравится, потому что тогда услуги пешехода становятся ответственностью звонящего, а не человека, и последовательность не гарантируется. Любой вызывающий абонент должен знать, какую службу использовать, чтобы гарантировать согласованность, в то время как сохранение ее в классе Person означает, что ее необходимо изменить вручную, чтобы отличалось поведение при ходьбе, но при этом допускается инверсия зависимостей.То, что вы ищете, это множественное наследование. Однако ни в C #, ни в Java его нет.
Вы можете расширить B из A. Это устранит необходимость в закрытом поле для B, а также в клее для перенаправления. Но вы можете сделать это только для одного из B, C или D.
Теперь, если вы можете сделать так, чтобы C наследовал от B, а D от C, тогда вам нужно иметь только A extends D ...;) - просто чтобы прояснить это, на самом деле я не поощряю это в этом примере, так как нет никаких указаний для этого.
В C ++ вы можете иметь наследование A от B, C и D.
Но множественное наследование делает программы труднее рассуждать и имеет свои проблемы; Кроме того, часто есть чистый способ избежать этого. Тем не менее, иногда без этого нужно найти компромисс между проектированием повторяющегося шаблона и тем, как раскрывается объектная модель.
Такое ощущение, что вы пытаетесь смешать композицию и наследование. Если бы это был C ++, вы могли бы использовать чистое решение наследования. Но так как это не так, я бы рекомендовал принять композицию.
источник