Неинкапсулированный означает неизменный?

Я наткнулся на эту строку в Effective C++:

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

Что автор подразумевает под «общедоступным означает неинкапсулированный, а практически говоря, неинкапсулированный означает неизменный»?

И как неинкапсулированный неизменяемый?


person Suhail Gupta    schedule 02.07.2011    source источник
comment
@ Martinho Fernandes Любая конкретная причина для удаления тега java?   -  person Suhail Gupta    schedule 02.07.2011
comment
Гупта: Потому что в книге конкретно говорится о C++.   -  person Puppy    schedule 02.07.2011
comment
@ DeadMG Но это общий вопрос. Я мог бы удалить первую строку в моем вопросе.   -  person Suhail Gupta    schedule 02.07.2011
comment
@Suhail: да, это общий вопрос ООП. Вот почему он не должен иметь тег Java. Или тег С++. Потому что речь идет не о каком-то конкретном языке; речь идет об инкапсуляции в целом.   -  person Nicol Bolas    schedule 02.07.2011


Ответы (4)


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

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

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

Это не вопрос правил C++; это просто вопрос правил дизайна интерфейса. Так как общедоступные вещи являются частью интерфейса, вы должны быть осторожны с тем, что вы делаете общедоступными.

person Nicol Bolas    schedule 02.07.2011
comment
... и что может быть нужно изменить? - person Suhail Gupta; 02.07.2011
comment
@Suhail: Идея состоит в том, чтобы никогда не нуждаться в изменениях. Вот почему вы должны тщательно выбирать то, что вы публикуете. Если вы все сделаете правильно, у вас будет возможность изменить детали реализации без изменения интерфейса. - person Nicol Bolas; 02.07.2011
comment
@ Никол Болас Как ваше утверждение Идея никогда не должна меняться. потерпит неудачу, если я сделаю всех своих членов общедоступными? - person Suhail Gupta; 02.07.2011
comment
@Suhail: Потому что мы предполагаем, что вы работаете в сфере разработки программного обеспечения, где вам необходимо изменить реализацию. Некоторые из этих членов не обязательно должны быть общедоступными, потому что они зависят от реализации. Если вы можете написать что-то один раз и никогда не прикасаться к этому, это здорово. Но хотите ли вы рискнуть, что вам никогда не придется касаться реализации, или вы действительно хотите использовать инкапсуляцию и скрытие данных, чтобы сделать возможными неизбежные изменения реализации, не затрагивая интерфейс? - person Nicol Bolas; 02.07.2011
comment
@Suhail: пример. Предположим, у вас есть класс, представляющий положение и ориентацию объекта, и предположим, что эти объекты могут быть жестко прикреплены друг к другу и отсоединены друг от друга. Когда вы перемещаете один объект, вы хотите, чтобы вся цепочка связанных объектов двигалась как один. За поддержание согласованности отвечает некоторый метод, назовем его update. Если данные могут быть установлены только каким-либо установщиком, этот установщик может гарантировать, что вызывается update(): состояние гарантированно будет непротиворечивым. Если данные открыты, какой-то пользователь неизбежно будет настраивать состояние, но не вызывать update(). - person David Hammen; 02.07.2011
comment
@David: это отличается от изменения реализации, речь идет о сохранении инвариантов (что также важно, но здесь вопрос не в этом). - person Matthieu M.; 02.07.2011
comment
@ Никол Болас Я думаю, что теперь я чувствую себя лучше, но один вопрос: Разве я не могу реорганизовать свой код с такой же легкостью, если бы я объявил элементы данных общедоступными? - person Suhail Gupta; 02.07.2011
comment
@Suhail: И как именно вы бы это сделали? Если ваш рефакторинг включает удаление общедоступных элементов данных, вы изменяете интерфейс. А это значит, что вы взламываете чужой код. Именно этого рефакторинг не должен делать. - person Nicol Bolas; 03.07.2011
comment
comment
@Suhail: это новый вопрос. И это слишком сложно, чтобы ответить в простом комментарии. Но подумайте, что произойдет, если вы захотите, чтобы NormalFieldClass содержал имя и фамилию по отдельности. В инкапсулированной версии пользователь может установить оба имени с помощью старой функции setName, но он также может использовать новые функции setFirstName и setLastName. Неинкапсулированную версию нельзя обновить, не нарушив существующий код, поскольку пользователи просто нажимают на данные напрямую. - person Nicol Bolas; 03.07.2011
comment
@ Никол Болас Я изменил обычный класс и опубликовал его как.... - person Suhail Gupta; 03.07.2011

Инкапсуляция — это идея о том, что вы можете получить доступ к члену данных класса только через методы интерфейса. Результатом использования метода является «скрытие» фактической реализации члена данных, так что вы можете изменить его без необходимости изменять код, который использует этот класс через методы интерфейса (при условии, что вы не меняете способ, которым они определенный).

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

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

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

«Правильный» способ управлять этим с помощью инкапсуляции - сделать элемент данных закрытым и определить метод интерфейса, например:

std::string getStringWithKey(int index);

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

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

person sergio    schedule 02.07.2011

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

person Community    schedule 02.07.2011

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

person user207421    schedule 02.07.2011
comment
Могу ли я никогда не изменять имя и тип элементов данных, объявленных общедоступными? ! - person Suhail Gupta; 02.07.2011
comment
Нет-нет, не как постоянное, а скорее как в том, что вы не можете изменить свой дизайн после того, как опубликовали свой интерфейс, потому что ваши пользователи уже начали использовать общедоступные члены. - person Kerrek SB; 02.07.2011
comment
@ Kerrek SB, почему я не могу изменить дизайн после того, как опубликовал свой интерфейс среди публичных участников? - person Suhail Gupta; 02.07.2011
comment
@Suhail, потому что клиентский код будет использовать и полагаться на то, что вы опубликовали. Если вы начнете менять свой общедоступный интерфейс, клиентам придется адаптировать свой код. - person juanchopanza; 02.07.2011
comment
@juanchopanza и какую пользу я получу, если у меня должным образом будут выбраны публичные участники? - person Suhail Gupta; 02.07.2011