Инкапсуляция. Хорошо продуманный класс - PullRequest
5 голосов
/ 21 октября 2010

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

Ответы [ 6 ]

10 голосов
/ 21 октября 2010

Это широко распространенная мысль?

В объектно-ориентированном мире - да.

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

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

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

Любой пример на PHP или Java был бы очень полезен.

Вот пример Java:

public class MyClass {
    // Should not be < 0
    public int importantValue;
    ...
    public void setImportantValue(int newValue) {
        if (newValue < 0) {
           throw new IllegalArgumentException("value cannot be < 0");
        }
    }
    ...
}

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

3 голосов
/ 21 октября 2010

Какими могут быть последствия не делать это?

Вся идея инкапсуляции заключается в том, что все знания о чем-либо, связанном с классом (кроме его интерфейса), находятся внутри самого класса. Например, разрешение прямого доступа к атрибутам возлагает ответственность за то, чтобы убедиться, что любые назначения действительны для кода, выполняющего назначение. Если определение того, что является действительным, изменится, вы должны пройти и проверить все, используя класс, чтобы убедиться, что они соответствуют. Инкапсуляция правила в методе «setter» означает, что вам нужно изменить его только в одном месте, и любой вызывающий пользователь, пытающийся сделать что-то смешное, может получить исключение в ответ. Есть много других вещей, которые вы можете захотеть сделать при изменении атрибута, и сеттер - это место для этого.

Является ли хорошей практикой спорный вопрос о том, допустим ли прямой доступ к атрибутам, у которых нет правил для их связывания (например, все, что вписывается в целое число). Я предполагаю, что использование геттеров и сеттеров - хорошая идея для согласованности, т. Е. Вы всегда знаете, что вы можете вызвать setFoo(), чтобы изменить атрибут foo без необходимости искать, можете ли вы сделать это напрямую. Они также позволяют вам подготовить класс к будущему, так что если у вас есть дополнительный код для выполнения, место для его размещения уже есть.

Лично я думаю, что использование геттеров и сеттеров выглядит неуклюже. Я бы скорее написал x.foo = 34, чем x.setFoo(34), и с нетерпением жду того дня, когда какой-нибудь язык предложит эквивалент триггеров базы данных для членов, которые позволят вам определить код, который запускается до, после или вместо назначений.

1 голос
/ 21 октября 2010

В Object Oriente Programming существует принцип, известный как (http://en.wikipedia.org/wiki/Open/closed_principle): POC -> Принцип Открытого и Закрытого . Этот принцип действует: дизайн класса скважины должен быть открыт для расширяемости (наследования), но закрыт для модификации внутренних элементов (инкапсуляция) . Это означает, что вы не сможете изменить состояние объекта, не позаботившись об этом.

Таким образом, новые языки изменяют только внутренние переменные (поля) через свойства (методы получения и установки в C ++ или Java). В C # свойства компилируются с методами в MSIL.

C #:

int _myproperty = 0;
public int MyProperty
{
    get { return _myproperty; }
    set { if (_someVarieble = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; }  }    
}

C ++ / Java:

int _myproperty = 0;
public void setMyProperty(int value) 
{
  if (value = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; }
}
public int getMyProperty() 
{
    return _myproperty;
}
1 голос
/ 21 октября 2010

Еще одна мысль для размышления

Инкапсуляция с помощью аксессоров также обеспечивает гораздо лучшую ремонтопригодность в будущем.В ответе Феанора, приведенном выше, он прекрасно работает для обеспечения проверок безопасности (при условии, что ваш instvar является частным), но он может принести гораздо больше пользы.

Рассмотрим следующий сценарий:
1) вы завершили свое заявление,и распространите его среди некоторого набора пользователей (внутренних, внешних и т. д.).
2) BigCustomerA подходит к вашей команде и хочет, чтобы в продукт был добавлен контрольный журнал.

Если каждый использует методы доступа в своем коде, это становится почти тривиальным для реализации.Примерно так:

MyAPI Версия 1.0

public class MyClass {
    private int importantValue;
    ...
    public void setImportantValue(int newValue) {
        if (newValue < 0) {
           throw new IllegalArgumentException("value cannot be < 0");
        }
        importantValue = newValue;
    }
    ...
}



MyAPI V1.1 (теперь с контрольными журналами)

public class MyClass {
    private int importantValue;
    ...
    public void setImportantValue(int newValue) {
        if (newValue < 0) {
           throw new IllegalArgumentException("value cannot be < 0");
        }
        this.addAuditTrail("importantValue", importantValue, newValue);
        importantValue = newValue;
    }
    ...
}

Существующие пользователиAPI не вносит изменений в свой код, и теперь доступна новая функция (контрольный журнал).
Без инкапсуляции с использованием методов доступа вы столкнулись с огромными усилиями по миграции.


При первом кодировании, это будет похоже на большую работу.Набирать текст намного быстрее: class.varName = something против class.setVarName(something);, но если бы все пошли простым путем, получить оплату за запрос функции BigCustomerA было бы огромным усилием.

1 голос
/ 21 октября 2010

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

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

Позвольте мне добавить следующее: Это зависит.Инкапсуляция (на вспомогательном языке) дает вам некоторый контроль над тем, как используются ваши классы, поэтому вы можете сказать людям: это API, и вы должны его использовать.В других языках (например, Python) разница между официальным API и неофициальными (могут быть изменены) интерфейсами заключается только в соглашении об именах (в конце концов, мы все согласны со взрослыми )

Инкапсуляцияне является функцией безопасности.

0 голосов
/ 01 марта 2013

Взять тезисы идей (от Head First C # ):

  • Подумайте о способах неправильного использования полей. Что может пойти не так, если они установлены неправильно.
  • Все в вашем классе публично? Потратьте некоторое время на размышления об инкапсуляции.
  • Какие поля требуют обработки или расчета? Они главные кандидаты.
  • Делайте поля и методы общедоступными, только если это необходимо. Если у вас нет причин объявлять что-либо публичным, не делайте этого.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...