Это - хорошая практика для потери сознания наследуемой функциональности, которая не будет использоваться?

Я задаюсь вопросом, должен ли я изменить программную архитектуру одного из моих проектов.

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

Я работаю с тем, что мы называем "каналом" для передачи данных между устройством и хостом. Каждый канал должен быть реализован на стороне хоста и устройстве. У нас есть различные виды каналов, обычных и специальных каналов, которые передают измерительные данные.

Мое текущее решение имеет общий код в абстрактном базовом классе. Оттуда на коде разделяется между этими двумя сторонами. Поскольку это повернулось, там несколько случаев, когда мы совместно использовали бы код, но мы не можем совместно использовать его, мы должны реализовать его на каждой стороне.

Принцип DRY (не повторяют себя) говорит, что у Вас не должно быть кода дважды.

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

Это приемлемая вещь сделать:

public abstract class ChannelAbstract
{
    protected void ChannelAbstractMethodUsedByDeviceSide()    {  }
    protected void ChannelAbstractMethodUsedByHostSide()      {  }
}

public abstract class MeasurementChannelAbstract : ChannelAbstract
{
    protected void MeasurementChannelAbstractMethodUsedByDeviceSide()   {  }
    protected void MeasurementChannelAbstractMethodUsedByHostSide()     {  }
}

public class DeviceMeasurementChannel : MeasurementChannelAbstract
{
    public new void MeasurementChannelAbstractMethodUsedByDeviceSide()
    {
        base.MeasurementChannelAbstractMethodUsedByDeviceSide();
    }

    public new void ChannelAbstractMethodUsedByDeviceSide()
    {
        base.ChannelAbstractMethodUsedByDeviceSide();
    }
}

public class HostMeasurementChannel : MeasurementChannelAbstract
{
    public new void MeasurementChannelAbstractMethodUsedByHostSide()
    {
        base.MeasurementChannelAbstractMethodUsedByHostSide();
    }

    public new void ChannelAbstractMethodUsedByHostSide()
    {
        base.ChannelAbstractMethodUsedByHostSide();
    }
}

Теперь, DeviceMeasurementChannel только использует функциональность для стороны устройства от MeasurementChannelAbstract. Путем объявления всех методов/участников MeasurementChannelAbstract protected необходимо использовать new ключевое слово для добавления той функциональности, к которой получат доступ с внешней стороны.

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

9
задан Cœur 13 December 2017 в 05:22
поделиться

5 ответов

Мне кажется, что вы путаете наследование и композицию. Когда вам нужно «очистить» / выбросить исключение, когда унаследованные функции не перекрываются разумно, в вашем графе наследования отсутствует какой-то промежуточный класс. И часто это происходит потому, что некоторые функции просто должны исходить от экземпляра члена другого класса, а не наследоваться.

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

5
ответ дан 4 December 2019 в 14:27
поделиться

Поэтому я спрашиваю себя, нормально ли иметь единую цепочку наследования (принимая, что некоторые классы будут иметь функциональность как для хоста, так и для устройства ) и выполнить разделение на канал хоста / устройства на последнем этапе (отключив функциональность, которая {{1} }} не нужен)

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

0
ответ дан 4 December 2019 в 14:27
поделиться

Как подразумевает Rich: Необходим только ОДИН из членов, объявленных ins MeasurementChannelAbstract в одной из конкретных реализаций. очень четкое указание на то, что ваш интерфейс плохо определен, поскольку он несет более чем одну ответственность. Это означает, что клиентам вашего кода (и читателям) сложно понять абстракции и увидеть разницу между различными конкретными реализациями.

Это называется «Принцип единственной ответственности» , и он важен для хорошего объектно-ориентированного проектирования.

(Чтобы получить больше информации о хорошем объектно-ориентированном дизайне, я рекомендую проработать все принципы SOLID).

2
ответ дан 4 December 2019 в 14:27
поделиться

Мне кажется, что вы еще не закончили определять, какие биты кода используются совместно. Разве не было бы разумнее хранить все общие / общие материалы в MeasurementChannelAbstract вместо того, чтобы иметь разные методы, которые вызывают две стороны? Я бы подумал, что они должны быть в унаследованных классах?

0
ответ дан 4 December 2019 в 14:27
поделиться

Вы можете решить проблему с помощью наследования, например:

public abstract class MeasurementChannelAbstract
{
    protected abstract void Method();
}

public class DeviceMeasurementChannel : MeasurementChannelAbstract
{
    public void Method()
    {
        // Device side implementation here.
    }
}

public class HostMeasurementChannel : MeasurementChannelAbstract
{
    public void Method()
    {
        // Host side implementation here.
    }
}

... или путем композиции, используя шаблон стратегии, например:

public class MeasurementChannel
{
    private MeasurementStrategyAbstract m_strategy;

    public MeasurementChannel(MeasurementStrategyAbstract strategy)
    {
        m_strategy = strategy;
    }

    protected void Method()
    {
        m_strategy.Measure();
    }
}

public abstract class MeasurementStrategyAbstract
{
    protected abstract void Measure();
}

public class DeviceMeasurementStrategy : MeasurementStrategyAbstract
{
    public void Measure()
    {
        // Device side implementation here.
    }
}

public class HostMeasurementStrategy : MeasurementStrategyAbstract
{
    public void Measure()
    {
        // Host side implementation here.
    }
}

Мне кажется, что вы хотите разделить иерархию наследования между и стандартными / измерительными каналами и каналами устройства / хоста. Один из способов сделать это - множественное наследование, но C # не поддерживает множественное наследование (за исключением интерфейсов), и в большинстве случаев дизайн, основанный на композиции, будет проще.

7
ответ дан 4 December 2019 в 14:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: