Правильно ли использовать реализацию вместо абстракции или менять реализацию? - PullRequest
2 голосов
/ 01 ноября 2010

У меня есть ситуация, когда у меня есть 2 Activity объекты (скажем, пустые и запланированные действия, не контролируемые мной), которые разделяют несколько видов поведения, например, человек, который забронировал мероприятие, комната, где происходит это действие, вид деятельности, предмет и т. д.

Я создал два объекта-оболочки (EmptyWrapper и ScheduledWrapper), которые имеют суперкласс ActivityWrapper, который реализует некоторые методы, общие для обоих дочерних объектов, и имеет некоторые абстрактные методы / свойствадля детской оболочки, чтобы ответить соответственно.Они очень похожи по поведению, но есть одно существенное отличие: вы можете планировать действия, только если это пустое место!Структура выглядит примерно так (очень упрощенный код):

 public class EmptyWrapper : AppWrapper
 {
    EmptySlot _emptySlot;        

    public EmptySlotWrapper(EmptySlot emptySlot) : base()
    {
        this._emptySlot = emptySlot;
    }

    public override string Id
    {
        get { return _emptySlot.AgendaId; }
    }

    public override string Room;
    {
        get{ return _emptySlot.Room;}
    }

    public override string Person
    {
        get{ return _emptySlot.Person;}
    }

    public override string AppType;
    {
        get{ return "Empty";}
    }

    public override bool IsAppSlot()
    {
        return false;
    }

    public override bool IsEmptySlot()
    {
        return true;
    }

    public override bool CanPerformOperations()
    {
        return true;
    }

    public void ReserveApp(ObjWithActivityInfo actObj)
    {
        (...)            
    }
 }

ActivityWrapper похож, но объект обтекания отличается, bools возвращает true для IsAppSlot, false для IsEmptySlot иfalse для CanPerformOperations, и ReserveApp() метод отсутствует.

Следующий базовый класс:

public abstract class AppWrapper
{
    public abstract string Collaborator { get; }
    public abstract string Room { get; }
    public abstract string AppType { get;}

    public AppWrapper()
    { }

    public abstract bool IsAppSlot();
    public abstract bool IsEmptySlot();

    public abstract bool CanPerformOperations();

    public virtual string GetTextToShow()
    {
        return Person + " - " + Room;
    }

    (...)
}

В моем коде я хотел сослаться только на ActivityWrapper, потому что дляобщие операции (показать информацию и внешний вид) мне не нужны реализации.Проблема возникает, когда мне нужно забронировать деятельность для пустых слотов.В этом пункте в моем коде я преобразую AppointmentWrapper в EmptyWrapper и резервирую слот для действия (это все еще EmptySlot, но оно зарезервировано для выбранного действия), в противном случае, если приведение было неудачнымЯ ничего не делаю, потому что это был неправильный Activity тип.

Это правильно, или я должен реализовать метод ReserveActivity() в обеих оболочках и иметь ActivityWrapper ничего не делать?

Или я должен сделать это по-другому?Может быть, изменить структуру классов?

Извините за длинный текст.

Ответы [ 2 ]

1 голос
/ 21 июня 2011

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

например,

public interface IAppSlotContainer
{
    void relevant_Method_When_ObjectIsAppSlot();
}

public interface IEmptySlotContainer
{
    void relevant_Method_When_ObjectIsEmptySlot();
}

public class EmptyWrapper : AppWrapper, IAppSlotContainer, IEmptySlotContainer
{

public EmptyWrapper(EmptySlot emptySlot) : base()
{
    this._emptySlot = emptySlot;
}

public override string Id
{
    get { return _emptySlot.AgendaId; }
}

public void relevant_Method_When_ObjectIsEmptySlot()
{
}

public void relevant_Method_When_ObjectIsAppSlot()
{   
}

}

Затем вместо того, чтобы перезаписать абстрактный метод "IsEmpty" и реализовать его как "return true", просто проверьте, является ли объектэкземпляр IEmptySlotContainer, приведите его к этому интерфейсу и выполните команду, связанную с интерфейсом.это намного более универсально и изящно на мой вкус ...

Надеюсь, это поможет ...

1 голос
/ 01 ноября 2010

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

Я бы сделал безопасный бросок ...

var i = obj as theClass

, а затем проверить на ноль. Я бы использовал немного linq, чтобы выбрать все объекты, которые имеют свойство, которое вы определили, чтобы указать, для какого типа они установлены в true.

Вы могли бы сделать это иным способом и сэкономить себя на приведении и тестировании, но это означает, что дизайн менее очевиден для постороннего.

Я думаю, это дело вкуса, но я предпочитаю, как ты это сделал. Я не уверен, что мне нравятся свойства bool для определения типа. Что если вы снова унаследуете базовый класс? Кроме того, вы можете привести тип к типу, который с более глубокой структурой объекта может быть более полезным.

Я согласен с вашим желанием работать с коллекцией абстрактного класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...