2017-01-13 1 views
2

Я видел несколько примеров использования интерфейса поставщика по адресу https://dzone.com/articles/supplier-interface.Зачем использовать `java.util.function.supplier`, когда можно просто вызвать метод?

Мой вопрос, если в приведенном выше примере, я мог бы сделать что-то, как легко, как:

driveVehicle(new Vehicle()); 
driveVehicle(new Car()); 

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

+2

Что делать, если вы хотите, чтобы значение не было жестко запрограммировано? – chrylis

+1

Что делать, если вам нужна вещь, которая может генерировать новые автомобили «на лету», но вы не хотите, чтобы код, который их потреблял, имел дело с логикой их создания? 'new VehiclePainter (vehicleSupplier)' - художнику все равно, откуда берутся транспортные средства, или это автомобили или грузовики или самолеты. Он просто берет транспортные средства, которые поставщик поставляет, и рисует их. – yshavit

+0

@yshavit можете ли вы прокомментировать какой-нибудь код? – AmeyaKetkar

ответ

6

Предположим, у вас есть параметры, хранящиеся в базе данных, которые вы хотите сохранить в постоянной во всем приложении

// Assume retrieveSystemParameter query database which allows to change parameters 
public static String SYSTEM_PARAMETER = StaticUtilities.retrieveSystemParameter(); 

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

public static Supplier<String> SYSTEM_PARAMETER_SUPPLIER = StaticUtilities::retrieveSystemParameter; 

Когда вам нужно значение где-то позвонит SYSTEM_PARAMETER_SUPPLIER.get() при необходимости, которая будет извлекать параметр в базе данных - таким образом, если изменить параметр в базе данных, вы выиграли не нужно передислоцировать.

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


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

4

Я предполагаю, что необязательный вариант может быть идеальным примером. Рассмотрим следующий фрагмент:

final Product firstProduct = Optional.ofNullable(product) 
     .orElse(productDao.findProductById(id)); 

final Product secondProduct = Optional.ofNullable(product) 
     .orElseGet(() -> productDao.findProductById(id)); 

Вы получаете продукт, который может быть пустым. Чтобы определить firstProduct, java придется вызывать выражение в методе orElse, поэтому независимо от того, какой продукт имеет значение null, или нет, вам всегда нужно определить значение, которое будет возвращено в случае, если произведение равно null.

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

1

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

Рассмотрим, например, следующий пример:

public class TestClass { 

    private String field; 

    public String getField() { 
     return field; 
    } 

    public void method(Supplier<String> supplier) { 
     field = "This is"; 
     System.out.println(supplier.get() + " a test"); 
    } 

    public static void main(String[] args) { 
     TestClass c = new TestClass(); 
     c.method(() -> c.getField()); 
    } 
} 

Здесь method() не является чистым, поскольку он изменяет значение field, который используется позже в лямбда (через вызов метода getField()). Когда лямбда вызывается на месте (т., когда вызывается get()), вызов getField() произойдет после установка поля. Другими словами, method() принимает Supplier<String> вместо String, чтобы клиенты могли безопасно вызвать метод getField().

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

1

Поставщик добавляет еще один уровень косвенности.

Учитывая, что "All problems in computer science can be solved by another level of indirection", вполне вероятно, что есть проблемы, которые могут быть решены с помощью Поставщика.

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

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

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

0

Вы можете использовать поставщик в карты на базе фабрики класса

public class StackService { 
    final static String INTEGERS = "Integers"; 
    final static String DOUBLES = "Doubles"; 
    final static String STRINGS = "Strings"; 

    final static Map<String, Supplier<Stack>> stackType; 

    static { 
     stackType = new HashMap<>(); 
     stackType.put(INTEGERS, Stack<Integer>::new); 
     stackType.put(DOUBLES, Stack<Double>::new); 
     stackType.put(STRINGS, Stack<String>::new); 
    } 

    public Stack<?> createStackOfType(String stackType) { 
     return stackType.get(stackType).get(); 
    } 
} 

Вот если бы вы просто использовать new Stack() вы бы возвращает ссылку на тот же объект, а не новый.

Смежные вопросы