2010-08-26 4 views
1

У меня есть несколько классов C#, называемых ShapeA, ShapeB, ShapeC и т. Д. И класс коллекции ShapeCollection. все они наследуются от абстрактного класса под названием «Геометрия». Все эти классы прибывают из сторонней сборки, поэтому я не могу их изменить.Внедрение нового интерфейса без создания производного типа

Я хочу также добавить новый метод ко всем этим классам Shape, назовем его Paint() и реализовать этот метод по-разному для каждого класса Shape. Класс ShapeCollection просто вызовет этот метод Paint() для каждого класса формы в коллекции.

Самый простой способ, которым я думал сделать это, - создать новый класс для каждого класса формы, который наследует исходный класс формы, но также будет реализовывать интерфейс, который будет содержать метод Paint().

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

Каков правильный способ сделать это?

+0

Как выглядит ваш ShapeCollection? Полагаю, коллекция - это ваш собственный класс? У вас есть ShapeACollection, ShapeBCollection и т. Д.? Или это всего лишь одна коллекция со всеми формами? – GenericTypeTea

+0

Чтобы уточнить: ShapeCollection является частью третьей стороны. Он содержит коллекцию объектов геометрии. Это означает, что он может содержать экземпляры разных классов формы. Причина, по которой я упоминал о существовании ShapeCollection, заключается в том, что я думал об использовании методов расширения, но затем в методе Paint() ShapeCollection у меня не было бы обычного способа вызвать метод Paint() для разных Экземпляры формы. –

ответ

2

Почему бы не использовать метод расширения?

namespace YourProject.Extensions 
{ 
    public static class ShapeExtensions 
    { 
     public static void Paint(this ShapeA shape) 
     { 
      // Your paint code 
     } 
     public static void Paint(this ShapeB shape) 
     { 
      // Your paint code 
     } 
     public static void Paint(this ShapeC shape) 
     { 
      // Your paint code 
     } 
    } 
} 

Тогда нет необходимости создавать новый класс, который наследует от Shape классов.

Затем в вашем ShapeCollection вы можете просто вызвать методы в обычном режиме (помните, что в пространство имен, где методы расширения находятся в ваших операциях), можно указать пространство имен.

UPDATE:

Просто, чтобы удовлетворить критиков - это будет работать только если вы имеете дело с самими реальными классами. То есть если вы делаете:

ShapeA shape = new ShapeA(); 
shape.Paint(); // This will work 

Но:

Geometry shape = new Shape(); 
shape.Paint(); // This will not exist 

Методы расширения будут доступны только при использовании класса напрямую.

+0

Это не сработало бы с ее «ShapeCollection», если только он не использовал отражение, чтобы найти метод расширения. – Ani

+1

@Ani - все будет хорошо. Если я не понял этот вопрос, это будет работать отлично. – GenericTypeTea

+0

@GenericTypeTea: Вы не можете делать: Geometry a = new ShapeA(); a.Paint(); Затем вам нужно создать метод расширения в классе Geometry для отправки вправо Paint в правильном типе. Но это будет довольно грязно. –

1

decorator Pattern может быть полезен здесь. Это не оборачивается проблемой многих имплантируемых классов.

1

Я попытался поместить это в комментарий к ответу GenericTypeTea, но форматирование не получилось.

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

public static void Paint(this Geometry shape) 
{ 
    if (shape is ShapeA) 
     ((ShapeA)shape).Paint(); 
    else if (shape is ShapeB) 
     ((ShapeB)shape).Paint(); 
    else if (shape is ShapeC) 
     ((ShapeC)shape).Paint(); 
    else 
     throw new InvalidOperationException("Can't paint " + shape.GetType().FullName); 
} 

В качестве альтернативы можно привести в порядок безобразия с простой иерархией классов и фабричным методом.

interface IShapePainter 
{ 
    void Paint(Geometry shape); 
} 

static class ShapeExtensions 
{ 
    public static IShapePainter GetPainter(Geometry shape) 
    { 
     if (shape is ShapeA) 
      return new ShapeAPainter(); 
     // Add other painters here 
     else 
      return null; 
    } 

    public static void Paint(this Geometry shape) 
    { 
     GetPainter(shape).Paint(shape); 
    } 
} 

abstract class ShapePainter<T> : IShapePainter 
    where T : Geometry 
{ 
    public abstract void Paint(T shape); 

    void IShapePainter.Paint(Geometry shape) 
    { 
     this.Paint((T)shape); 
    } 
} 

class ShapeAPainter : ShapePainter<ShapeA> 
{ 
    public override void Paint(ShapeA shape) 
    { 
     // Your paint code 
    } 
} 

Вы бы тогда нужно обновить GetPainter с каждой реализации ShapePainter соответствующих всем форм вы можете рисовать. Общий класс не является строго необходимым, так как вы можете реализовать интерфейс непосредственно на ShapeAPainter, но он сохраняет дублирование приведения каждого раза при его реализации.

Смежные вопросы