Цель членов парламента, не занимающих официального поста в классе

Каковы цели наличия частных/защищенных членов класса/структуры в объектно-ориентированном программировании? Каков вред в наличии всех участников быть общедоступным?

24
задан Jim G. 3 March 2010 в 21:14
поделиться

10 ответов

Encapsulation. Т.е. скрытие реализации данных вашего класса. Это позволяет вам изменить ее позже, не ломая весь клиентский код. Например, если у вас есть

class MyClass {
    public int foo;
}

ваши клиенты могут написать код типа

MyClass bar = new MyClass();
bar.foo++;

теперь, если вы понимаете, что foo на самом деле должно быть double, а не int, вы меняете его:

class MyClass {
    public double foo;
}

и код клиента не компилируется :-(

С хорошо разработанным интерфейсом, изменение внутренних частей (private parts) может даже включать превращение переменной-члена в вычисление или наоборот:

class Person {
    public String getName();
    public String getStreetAddress();
    public String getZipCode();
    public String getCountryCode();
    public int hashCode();
}

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

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

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

    public void setCountryCodeAndZip(String countryCode, String zipCode);

Однако с публичными полями у вас просто нет таких возможностей.

Особый случай использования приватных полей - неизменяемые объекты; это очень распространено, например, в Java, примерами являются String и BigDecimal. Эти классы вообще не имеют публичных сеттеров, что гарантирует, что их объекты, будучи созданными, не изменят своего состояния. Это позволяет оптимизировать производительность, а также упрощает их использование, например, в многопоточных программах, ORM и т.д.

27
ответ дан 28 November 2019 в 22:51
поделиться

Вы можете прочитать тему Скрытие информации в Википедии.

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

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

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

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

9
ответ дан 28 November 2019 в 22:51
поделиться

Красиво объяснено в Раздел 7.4: Защита личных частей этого онлайн-руководства по C ++ .

Зачем возиться с этим?

Спецификаторы позволяют классу быть очень сложным, с множеством функций-членов и элементов данных, имея при этом простой открытый интерфейс которые могут использовать другие классы . Класс, который имеет две сотни членов данных и сто функций-членов, может быть очень сложным для написания; но если есть только три или четыре общедоступных функции-члена , а все остальные частные, кому-то может быть легко научиться использовать класс. Ему только нужно понимать, как использовать небольшую горстку общедоступных функций, а не нужно беспокоиться о двух элементах данных, потому что ему не разрешен доступ к этим данным. Он может получить доступ к личным данным только через открытый интерфейс класса. Без сомнения, в небольшой программе использование этих спецификаторов может показаться ненужным. Однако их стоит понять , если вы планируете делать какую-либо программу разумного размера (более пары сотен строк). В общем, рекомендуется сделать члены данных закрытыми. Функции-члены, которые должны вызываться извне класса, должны быть общедоступными, а функции-члены которые вызываются только из класса (также известного как "вспомогательные функции") , вероятно, должны быть закрытыми. Эти спецификаторы особенно полезны в большой программе, в которой задействовано более одного программиста.

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

Вот класс ParameterIO , который считывает и записывает вектор целочисленных параметров

class ParameterIO
{
public:
    // Main member
    vector<int> *Params;
    string param_path;

    // Generate path
    void GeneratePath()
    {       
        char szPath[MAX_PATH];
        sprintf(szPath,"params_%d.dat",Params->size());
        param_path = szPath;
    }

    // Write to file
    void WriteParams()
    {
        assert_this(!Params->empty(),"Parameter vector is empty!");
        ofstream fout(param_path.c_str());
        assert_this(!fout.fail(),"Unable to open file for writing ...");
        copy(Params->begin(),Params->end(),ostream_iterator<int>(fout,"\n"));
        fout.close();
    }

    // Read parameters
    void ReadParams(const size_t Param_Size)
    {
        // Get the path
        Params->resize(Param_Size);
        GeneratePath();
        // Read
        ifstream fin(param_path.c_str());
        assert_this(!fin.fail(),"Unable to open file for reading ...");
        // Temporary integer
        for(size_t i = 0; i < Params->size() && !fin.eof() ; ++i) fin>>(*Params)[i];
        fin.close();
    }

    // Constructor
    ParameterIO(vector<int> * params):Params(params)
    {
        GeneratePath();
    }

    // Destructor
    ~ParameterIO()
    {
    }      

    // Assert
    void assert_this(const bool assertion, string msg)
    {
        if(assertion == false) 
        {
            cout<<msg<<endl;
            exit(1);
        }
    }
};

Следующий код разрушает этот класс:

const size_t len = 20;
vector<int> dummy(len);
for(size_t i = 0; i < len; ++i) dummy[i] = static_cast<int>(i);
ParameterIO writer(&dummy);

// ParameterIO breaks here!
// param_path should be private because 
    // the design of ParameterIO requires a standardized path
writer.param_path = "my_cool_path.dat";
// Write parameters to custom path
writer.WriteParams();

vector<int> dunce;
ParameterIO reader(&dunce);
// There is no such file!
reader.ReadParams(len);
7
ответ дан 28 November 2019 в 22:51
поделиться

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

Автомобиль должен управлять этим изнутри (конфиденциально), и пользователь должен быть защищен от прямого вмешательства в него ( инкапсуляция ) по очевидным причинам.

5
ответ дан 28 November 2019 в 22:51
поделиться

Каковы цели наличия внутренних органов в человеческом теле? Какой вред в том, что все органы находятся снаружи?

Совершенно верно!

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

1
ответ дан 28 November 2019 в 22:51
поделиться

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

Никакого вреда, в зависимости от аудитории и потребления класса.

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

Итак, вам действительно нужно посмотреть, как класс будет потребляться и кем, прежде чем вы сможете даже начать отвечать на этот вопрос. Точно так же, как долго будет длиться жизненный цикл разработки программного обеспечения? Это месяцы? Годы? Десятилетия? Будут ли другие люди, кроме вас, использовать этот класс?

Чем более «общедоступным» класс (т. Е. Чем больше людей будут потреблять и использовать класс), тем важнее создать надежный общедоступный интерфейс и придерживаться его.

1
ответ дан 28 November 2019 в 22:51
поделиться

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

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

Кроме того, в Java, например, у вас нет возможности ограничить доступ к переменной-члену без изменения ее видимости, поэтому вы часто обнаруживаете, что преждевременно создаете геттеры и сеттеры и делаете саму переменную частной или защищенной. В Python, например, этой проблемы не существует, потому что вы можете заставить геттеры и сеттеры вести себя как переменные для прямого доступа (там они называются свойствами).

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

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

4
ответ дан 28 November 2019 в 22:51
поделиться

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

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

3
ответ дан 28 November 2019 в 22:51
поделиться

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

1
ответ дан 28 November 2019 в 22:51
поделиться

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

Многие люди аргументируют это, например, «вы не хотите, чтобы все это читали», но я думаю, что ограничение на установку значения является более удобным примером.

0
ответ дан 28 November 2019 в 22:51
поделиться
Другие вопросы по тегам:

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