Pull to refresh

Как модификаторы доступа тормозят развитие молодых специалистов

Reading time3 min
Views5.4K
Большинство популярных ОО языков предоставляют такой инструмент, как модификатор доступа к методу или полю. И это хорошо для опытных программистов, но это не то, с чего надо начинать знакомство с инкапсуляцией. Ниже я объясню почему.



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

В общем виде инкапсуляция определяется как средство сокрытия внутренней реализации объекта от клиента с целью сохранения целостности объекта и сокрытия сложности этой самой внутренней реализации.

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

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


Видимость полей, обозначенный разными модификаторами доступа в 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() {
        // ...
    }
}

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

Более того, интерфейсы заставляют осознанно выбирать какие возможности от объекта может получать какой клиент. То есть у нас есть возможность предоставить абсолютно несвязанные протоколы для разных клиентов, тогда как модификаторы не различают клиентов. Это большой плюс в пользу интерфейсов.
Tags:
Hubs:
Total votes 23: ↑2 and ↓21-18
Comments23

Articles