Большинство популярных ОО языков предоставляют такой инструмент, как модификатор доступа к методу или полю. И это хорошо для опытных программистов, но это не то, с чего надо начинать знакомство с инкапсуляцией. Ниже я объясню почему.
Дисклеймер. Эта статья не является призывом к действию и не утверждает, что есть единственный рассово верный способ сокрыть данные. Эта статья сделана с целью предложить читателю, возможно, новый взгляд на инкапсуляцию. Существует много ситуаций, где модификаторы доступа предпочтительней, однако это не повод умалчивать об интерфейсах.
В общем виде инкапсуляция определяется как средство сокрытия внутренней реализации объекта от клиента с целью сохранения целостности объекта и сокрытия сложности этой самой внутренней реализации.
Добиться такого сокрытия можно несколькими способами. Одним является использование модификаторов доступа, другим — использование интерфейсов (протоколов, заголовочных файлов, ...). Есть и другие хитрые возможности, но статья не о них.
Модификаторы доступа на первый взгляд могут показаться более мощным средством с точки зрения сокрытия реализации, поскольку дают контроль над каждым полем в отдельности и дают больше опций доступа. В действительности же это отчасти просто шорткат для создания нескольких интерфейсов к классу. Модификаторы доступа дают возможности не шире, чем интерфейсы, поскольку с помощью них выражаются, кроме одной детали. О ней ниже.
Видимость полей, обозначенный разными модификаторами доступа в Java.
В фрагменте кода ниже представлен класс с модификаторами доступа к методам и эквивалетные представления в виде интерфейсов.
Протоколы имеют ряд преимуществ. Достаточно упомянуть то, что это основное средство реализации полиморфизма в ООП, которое доходит до новичков сильно позже, чем могло бы.
Единственная сложность подходя с протоколами состоит в том, что надо контролировать процесс создания объектов. Порождающие шаблоны нужны именно для того чтоб оградить опасный код, содержащий конкретные типы от чистого кода, работающего с интерфейсами. Соблюдая это простое правило, мы получаем ту же самую инкапсуляцию, что и использованием спецификаторов, но при этом получаем большую гибкость.
Такой код на C#
будет эквивалентен такому по возможностям для клиента.
Из-за существования модификаторов доступа, новички очень долго не узнают об интерфейсах. От этого они не пользуются настоящей мощью ООП. То есть происходит некоторая подмена понятий. Модификаторы доступа — несомненно атрибут ООП, но они же перетягивает одеяло с интерфейсов, которые раскрывают ООП гораздо сильнее.
Более того, интерфейсы заставляют осознанно выбирать какие возможности от объекта может получать какой клиент. То есть у нас есть возможность предоставить абсолютно несвязанные протоколы для разных клиентов, тогда как модификаторы не различают клиентов. Это большой плюс в пользу интерфейсов.
Дисклеймер. Эта статья не является призывом к действию и не утверждает, что есть единственный рассово верный способ сокрыть данные. Эта статья сделана с целью предложить читателю, возможно, новый взгляд на инкапсуляцию. Существует много ситуаций, где модификаторы доступа предпочтительней, однако это не повод умалчивать об интерфейсах.
В общем виде инкапсуляция определяется как средство сокрытия внутренней реализации объекта от клиента с целью сохранения целостности объекта и сокрытия сложности этой самой внутренней реализации.
Добиться такого сокрытия можно несколькими способами. Одним является использование модификаторов доступа, другим — использование интерфейсов (протоколов, заголовочных файлов, ...). Есть и другие хитрые возможности, но статья не о них.
Модификаторы доступа на первый взгляд могут показаться более мощным средством с точки зрения сокрытия реализации, поскольку дают контроль над каждым полем в отдельности и дают больше опций доступа. В действительности же это отчасти просто шорткат для создания нескольких интерфейсов к классу. Модификаторы доступа дают возможности не шире, чем интерфейсы, поскольку с помощью них выражаются, кроме одной детали. О ней ниже.
Видимость полей, обозначенный разными модификаторами доступа в Java.
В фрагменте кода ниже представлен класс с модификаторами доступа к методам и эквивалетные представления в виде интерфейсов.
public class ConsistentObject {
public void methodA() { /* ... */ }
protected void methodB() { /* ... */ }
void methodC() { /* ... */ }
private void methodD() { /* ... */ }
}
public interface IPublicConsistentObject {
void methodA() { /* ... */ }
}
public interface IProtectedConsistentObject: IPublicConsistentObject {
void methodB() { /* ... */ }
}
public interface IDefaultConsistentObject: IProtectedConsistentObject {
void methodC() { /* ... */ }
}
Протоколы имеют ряд преимуществ. Достаточно упомянуть то, что это основное средство реализации полиморфизма в ООП, которое доходит до новичков сильно позже, чем могло бы.
Единственная сложность подходя с протоколами состоит в том, что надо контролировать процесс создания объектов. Порождающие шаблоны нужны именно для того чтоб оградить опасный код, содержащий конкретные типы от чистого кода, работающего с интерфейсами. Соблюдая это простое правило, мы получаем ту же самую инкапсуляцию, что и использованием спецификаторов, но при этом получаем большую гибкость.
Такой код на C#
public class DataAccessObject {
private void readDataFromFixedSource() {
// ...
}
public byte[] getData() {
// ...
}
}
будет эквивалентен такому по возможностям для клиента.
public class DataAccessObjectFactory {
public IDataAccessObject createNew() {
return new DataAccessObject();
}
}
public interface IDataAccessObject {
byte[] getData();
}
class DataAccessObject: IDataAccessObject {
void readDataFromFixedSource() {
// ...
}
public byte[] getData() {
// ...
}
}
Из-за существования модификаторов доступа, новички очень долго не узнают об интерфейсах. От этого они не пользуются настоящей мощью ООП. То есть происходит некоторая подмена понятий. Модификаторы доступа — несомненно атрибут ООП, но они же перетягивает одеяло с интерфейсов, которые раскрывают ООП гораздо сильнее.
Более того, интерфейсы заставляют осознанно выбирать какие возможности от объекта может получать какой клиент. То есть у нас есть возможность предоставить абсолютно несвязанные протоколы для разных клиентов, тогда как модификаторы не различают клиентов. Это большой плюс в пользу интерфейсов.