Как стать автором
Обновить

О компонентах и интерфейсах. Java

Время на прочтение3 мин
Количество просмотров14K
Вступление

В предыдущей статье я написал о разных способах оформления интерфейсов к компонентам и сокрытия их реализации в C++.
В этой статье расскажу вкратце, как в Java отделить интерфейс от реализации, а реализацию скрыть.
Я не буду рассматривать компоненты разных там Java EE, я рассмотрю самые обычные jar-ники-библиотеки.
Итак.

Что мы имеем

В Java нет функций, есть только классы, соответственно в Java экспортируются классы.
Чтобы класс был экспортирован, нужно чтобы он был объявлен как public.
Итак, чтобы написать интерфейс библиотеки, нужна, собственно, сама библиотека и объявление экспортируемых классов как public.

Что-то типа того:

package com.test;

public class Test {
    private final String string = "Test";

    public String GetString()
    {
        return string;
    }
}

Компилируем, получаем jar-ник, который затем может использовать.
Ну как-то так:

package com.sample;

import com.test.Test;

public class NewClass {
    private static Test test = new Test();
    
    public static void Main()
    {
        System.out.println( test.GetString() );
    }
}

Какие в таком подходе недостатки.
Хоть скомпилированный jar-ник и скрывает реализацию, но у нас остаются доступными все public-методы классов библиотеки. Например если у нас jar-ник состоит из нескольких пакетов (Package-й), и мы использовали в нем вызовы методов между ними, то получится, что разработчик, использующий вашу библиотеку, сможет получить доступ к методам, которые вы не хотели открывать для использования. Т.е. мы опять же открываем реализацию. Так же мы не имеем текстов интерфейсов, которые бы могли отдать разработчикам для изучения.
Что делать в таком случае?
Чтобы полностью скрыть реализацию воспользуется одними из самых удобных инструментов Java — интерфейсами и рефлексией.

Что получилось

Например, у нас есть компонент с таким интерфейсом:
package com.iface;

public interface Component {
    
    public void Method1();

    public void Method2();

    public void Method3();

    public void Method4();
}

Экземпляры компонента создаем фабрикой, которая реализует вот такой интерфейс:
package com.iface;

public interface Factory {
    public Component getComponent();
}

Экземпляр фабрики создаем статически. Ссылку на фабрику сохраняем. Оформляем классом FactoryCreator следующим образом:
package com.iface;

import java.lang.reflect.Method;

public class FactoryCreator {
    private static Factory instance = null;
    private static Throwable ex = null;

    static {
        try {
            Class cl = Class.forName("com.test.FactoryImpl");
            Method method = cl.getMethod("createInstance", new Class[0]);
            Object obj = method.invoke(cl, new Object[0]);
            if(obj instanceof Factory) {
                instance = (Factory) obj;
            }
            ex = new Exception("Cannot init Factory instance.");
        } catch (Throwable throwable) {
            ex = throwable;
        }
    }

    public static Factory getInstance() throws Throwable {
        if(instance != null) {
            return instance;
        }
        
        throw ex;
    }
}

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

Резюме

Используя предложенный подход можно получить много плюсов в разработке. Ну взять хотя бы такую ситуацию. Мы ведем разработку сложной системы, в которой есть много взаимосвязанных компонентов.
Для параллельной разработки очень удобно разработать интерфейсы и сложить их в отдельные библиотеки. Тогда можно легко распараллелить разработку самих компонентов, их тестов, и компонентов, которые с ними связаны. Все будет прекрасно компилиться и собираться, хотя реализация при этом может быть еще не готова.
Теги:
Хабы:
Всего голосов 19: ↑5 и ↓14-9
Комментарии8

Публикации

Истории

Работа

Java разработчик
350 вакансий

Ближайшие события