Разве нет точки, где инкапсуляция становится смешной?

StackOverflow https://stackoverflow.com/questions/1712562

  •  19-09-2019
  •  | 
  •  

Вопрос

Для моего класса программного обеспечения для разработки программного обеспечения мы должны были создать программу типа «Feed Manager» для RSS -каналов. Вот как я справился с реализацией FeedItems.

Красиво и просто:

struct FeedItem {
    string title;
    string description;
    string url;
}

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

class FeedItem
{
public:
    FeedItem(string title, string description, string url);

    inline string getTitle() const { return this->title; }
    inline string getDescription() const { return this->description; }
    inline string getURL() const { return this->url; }

    inline void setTitle(string title) { this->title = title; }
    inline void setDescription(string description){ this->description = description; }
    inline void setURL(string url) { this->url = url; }

private:
    string title;
    string description;
    string url;
};

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


Это напоминает мне о том, как в C# люди всегда делают это:

public class Example
{
    private int _myint;

    public int MyInt
    {
        get
        {
            return this._myint;
        }
        set
        {
            this._myint = value;
        }
    }
}

Я имею в виду я ПОЛУЧИТЬ Почему они делают это, может быть, позже они хотят проверить данные в сеттере или увеличить их в Getter. Но почему бы тебе просто не сделать это ДО ТОГО КАК Эта ситуация возникает?

public class Example
{
    public int MyInt;
}

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

Это было полезно?

Решение

Это проблема «лучшей практики» и стиля.

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

Тогда есть также проблема повторного использования. Скажите, в будущем вам нужно изменить то, что происходит, когда кто -то обращается к члену данных. Вы можете сделать это, не заставляя клиентов перекомпилировать код. Вы можете просто изменить метод в классе и гарантировать, что новая логика используется.

Другие советы

Вот приятное долгое обсуждение по этому вопросу: Зачем использовать Getters и Setters.

Вопрос, который вы хотите задать себе: «Что произойдет через 3 месяца, когда понимаете это FeedItem.url делает Нужно быть подтверждено, но это уже упоминается непосредственно из 287 других классов? »

Основная причина сделать это до того, как это необходимо, - это для управления версиями.

Поля ведут себя иначе, чем свойства, особенно при использовании их в качестве LVALUE (где это часто не допускается, особенно в C#). Кроме того, если вам нужно, позже добавить свойства Get/установить процедуры, вы сломаете свой API - пользователи вашего класса должны будут переписать свой код, чтобы использовать новую версию.

Сделать это намного безопаснее.

C# 3, кстати, облегчает это:

public class Example
{
    public int MyInt { get; set; }
}

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

В вашем конкретном примере выше я вижу, что вы можете проверить, скажем, URL. Может быть, вы даже захотите продезинфицировать название и описание, но в любом случае я думаю, что это то, что вы можете сказать рано в дизайне класса. Укажите свои намерения и ваше обоснование в комментариях. Если вам не нужна проверка, вам не нужны Getter и Setter, вы абсолютно правы.

Простота оплачивает, это ценная функция. Никогда не делай ничего религиозно.

Если что -то является простой структурой, то да, это смешно, потому что это просто данные.

Это на самом деле просто возврат к началу ООП, где люди вообще не получали представления о занятиях. Нет причин иметь сотни методов GET и установить на случай, если вы можете изменить GetID (), чтобы когда -нибудь стать удаленным вызовом на телескоп Хаббла.

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

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

Видеть http://www.pragprog.com/articles/tell-dont-ask

Теперь давайте представим, что ваш FeedItem Класс стал удивительно популярным и используется проектами повсюду. Вы решаете, что вам нужно (как предложили другие ответы) подтвердите предоставленный URL -адрес.

Счастливые дни, вы написали сеттер для URL. Вы редактируете это, проверяете URL и бросаете исключение, если он недействителен. Вы выпускаете свою новую версию класса, и каждый, кто использует его, счастлив. (Давайте игнорируем проверенные против неконтролируемых исключений, чтобы сохранить это на треке).

За исключением того, что вам звонит от Angry Developer. Они читали список FeedItems из файла при запуске их приложения. И теперь, если кто -то совершает небольшую ошибку в файле конфигурации, ваше новое исключение брошено, а вся система не запускается, просто потому, что один из холодных элементов подачи был неправильным!

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

Имейте в виду, что кодирование «лучших практик» часто устарели от достижений в языках программирования.

Например, в C# концепция Getter/Setter была выпечена в языке в виде свойств. C# 3.0 облегчил это с внедрением автоматических свойств, где компилятор автоматически генерирует для вас Getter/Setter. C# 3.0 также ввели инициализаторы объектов, что означает, что в большинстве случаев вам больше не нужно объявлять конструкторы, которые просто инициализируют свойства.

Так что канонический способ сделать то, что вы делаете, будет выглядеть так:

class FeedItem
{
    public string Title { get; set; } // automatic properties
    public string Description { get; set; }
    public string Url { get; set; }
};

И использование будет выглядеть так (с помощью инициализатора объекта):

FeedItem fi = new FeedItem() { Title = "Some Title", Description = "Some Description", Url = "Some Url" };

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

Как разработчик C ++, я делаю своих участников всегда приватными просто для того, чтобы быть последовательными. Поэтому я всегда знаю, что мне нужно вводить px (), а не px

Кроме того, я обычно избегаю реализации методов сеттера. Вместо того, чтобы менять объект, я создаю новый:

p = Point(p.x(), p.y() + 1);

Это также сохраняет инкапсуляцию.

Абсолютно есть момент, когда инкапсуляция становится смешной.

Чем больше абстракции, которая вводится в код, тем больше будет ваше предварительное образование, будет стоимость обработки обучения.

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

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

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

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

Простые классы, которые вы создаете в классе, не достаточно иллюстрируют необходимость четко определенного интерфейса. Сказав: «Но почему бы вы не сделали это, пока не появится такая ситуация?» не будет работать в реальная жизнь. Анкет Что вы изучаете в своем курсе по разработке программного обеспечения, это разработка программного обеспечения, которое смогут использовать другие программисты. Учтите, что создатели библиотек, такие как, предоставленные .NET Framework и Java API абсолютно требуют этой дисциплины. Если бы они решили, что инкапсуляция была слишком большей проблемой, с этими средами было бы почти невозможно работать.

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

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

Геттеры/сеттеры, конечно, хороша, но они утомительны, чтобы писать и, что еще хуже, читать.

Сколько раз мы читали класс с полдюжины переменных членов и сопровождающими геттеры/сеттеры, каждый из которых с полным Hog @param/ @return html, кодированный, знаменитый бесполезный комментарий, такой как «Получить значение x», «Установите значение X ', «Получите значение y», «Установите значение y», «Получите значение z», «Установите значение Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz Удар!

Это очень распространенный вопрос: «Но почему бы вы не сделали это, пока не появится такая ситуация?». Причина проста: обычно гораздо дешевле не исправлять/повторно/повторно развернуть его позже, но сделать это правильно с первого раза. Старые оценки говорят, что затраты на техническое обслуживание составляют 80%, и большая часть этого обслуживания - это именно то, что вы предлагаете: делать правильные вещи только после того, как у кого -то возникла проблема. Делать это правильно в первый раз позволяет нам сосредоточиться на более интересных вещах и быть более продуктивными.

Неаккуратное кодирование обычно очень убыточно - ваши клиенты несчастны, потому что продукт ненадежна, и они не являются продуктивными, когда его используют. Разработчики тоже не счастливы - они проводят 80% времени, делая патчи, что скучно. В конце концов вы можете потерять как клиентов, так и хороших разработчиков.

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

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

Инкапсуляция теоретически полезна, если внутренняя реализация когда -либо меняется. Например, если URL-адрес для каждого объекта стал рассчитанным результатом, а не хранимым значением, то инкапсуляция geturl () будет продолжать работать. Но я подозреваю, что вы уже слышали эту сторону.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top