Почему важна степень видимости методов и атрибутов? - PullRequest
43 голосов
/ 12 сентября 2011

Почему бы не оставить все методы и атрибуты доступными откуда угодно (т.е. public)?

Можете ли вы привести пример проблемы, с которой я могу столкнуться, если объявлю атрибут как public?

Ответы [ 12 ]

146 голосов
/ 12 сентября 2011

Думайте о Макдональдсе как об объекте.Существует широко известный публичный способ заказа BigMac.

Внутри будет несколько других звонков, чтобы действительно получить материалы для изготовления этого Bigmac.Они не хотят, чтобы вы знали, как работает их цепочка поставок, поэтому все, что вы получаете, это публичный вызов Gimme_a_BigMac() и никогда не позволит вам получить доступ к методам Slaughter_a_cow() или Buy_potatoes_for_fries().

Для вашего собственного кода, который никто никогда не увидит, оставьте все открытым.Но если вы делаете библиотеку для повторного использования другими, тогда вы идете и защищаете внутренние детали.Это оставляет McDonald's возможность свободно переключаться на то, чтобы Скотти выбил себе пирожок, вместо того, чтобы вызывать компанию по транспортировке грузов, чтобы доставить мясо по суше.Конечный пользователь никогда не узнает разницу - он просто получает свой BigMac.Но внутренне все может кардинально измениться.

45 голосов
/ 12 сентября 2011

Почему нельзя оставлять все методы и атрибуты доступными из любого места (то есть общедоступного)?

Потому что это слишком дорого .

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

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

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

Частные методы не имеют ни одной из этих затрат. тратить деньги акционеров с умом; сделайте все частным, что вы можете.

12 голосов
/ 03 октября 2011

Думайте о сферах видимости как о внутренних кругах доверия.

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

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

10 голосов
/ 12 сентября 2011

Поскольку это нарушает концепцию инкапсуляции , ключевой принцип ООП.

9 голосов
/ 12 сентября 2011

Вы рискуете, говорите?

<?php

class Foo
{
    /**
     * @var SomeObject
     */
    public $bar;
}

Ваш код утверждает, что $bar должен содержать экземпляр объекта SomeObject.Однако любой, кто использует ваш код, может сделать

$myFoo->bar = new SomeOtherObject();

... и любой код, использующий Foo :: $ bar, являющийся SomeObject, сломается.С помощью методов получения и установки и защищенных свойств вы можете применить это ожидание:

<?php

class Foo
{
    /**
     * @var SomeObject
     */
    protected $bar;

    public function setBar(SomeObject $bar)
    {
        $this->bar = $bar;
    }
}

Теперь вы можете быть уверены, что в любое время, когда установлено значение Foo :: $ bar, оно будет иметь экземпляр объекта SomeObject.

4 голосов
/ 13 сентября 2011

Скрывая детали реализации, он также предотвращает попадание объекта в несогласованное состояние.

Вот искусственный пример стека (псевдокод).

public class Stack {

  public List stack = new List();
  public int currentStackPosition = 0;

  public String pop() {
    if (currentStackPosition-1 >= 0) {
      currentStackPosition--;
      return stack.remove(currentStackPosition + 1);
    } else {
      return null;
    }
  }

  public void push(String value) {
    currentStackPosition++;
    stack.add(value);
  }
}

Есливы делаете обе переменные приватными, реализация работает нормально.Но если вы общедоступны, вы можете легко нарушить его, просто установив неправильное значение для currentStackPosition или непосредственно изменив список.

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

2 голосов
/ 14 сентября 2011

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

Помните, что не вы, разработчик API, нарушаете инкапсуляцию, делая вещи открытыми.Это могут сделать пользователи класса, вызывая внутренние методы в их приложении.Вы можете либо дать им пощечину за попытку сделать это (например, объявив методы закрытыми), либо передать им ответственность (например, с помощью префикса не-API методов с помощью «_»).Вы действительно заботитесь о том, чтобы кто-то нарушил его код, используя вашу библиотеку другим способом, который вы советуете ему сделать?Я не знаю.

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

2 голосов
/ 13 сентября 2011

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

Простой пример: Предположим, мы создали класс Rectangle, который содержал четыре переменные - длину, ширину, площадь, периметр. Обратите внимание, что площадь и периметр получаются из длины и ширины (обычно я не делаю переменные для них), поэтому изменение длины приведет к изменению как площади, так и периметра.

Если вы не использовали правильное сокрытие информации (инкапсуляцию), тогда другая программа, использующая этот класс Rectangle, могла бы изменять длину без изменения области, и у вас был бы несовместимый Rectangle. Без инкапсуляции можно было бы создать прямоугольник длиной 1 и шириной 3 с площадью 32345.

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

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

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

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

1 голос
/ 15 апреля 2012

Чтобы спасти вас от себя!

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

Если вы следуете принципу наименьших привилегий, то принцип наименьшего знания (или Закон Деметры) и принцип одиночной ответственности не являютсядалеко позади.Так как ваш класс, который вы написали для загрузки последних результатов футбольных матчей, следовал этому принципу, и вы должны опрашивать его данные, а не сбрасывать их прямо в ваш интерфейс, вы копируете и вставляете весь класс в ваш следующий проект, экономя время разработки.Экономия времени на разработку - это хорошо.

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

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

1 голос
/ 17 сентября 2011

Вы можете подумать, что предыдущие ответы являются «теоретическими», если вы используете public свойства в Doctrine2 Entities, вы нарушаете ленивую загрузку.

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