我在https://dzone.com/articles/supplier-interface看到了一些使用供应商界面的例子。
我的问题是,如果在上面的例子中我可以做一些简单的事情:
driveVehicle(new Vehicle());
driveVehicle(new Car());
为什么要使用供应商界面,如果只是调用方法,而不接受任何参数。
答案 0 :(得分:8)
假设您在数据库中存储了要在整个应用中保持不变的参数
// 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()在特定的时间间隔。
答案 1 :(得分:5)
我认为Optional可能是完美的例子。请考虑以下代码段:
final Product firstProduct = Optional.ofNullable(product)
.orElse(productDao.findProductById(id));
final Product secondProduct = Optional.ofNullable(product)
.orElseGet(() -> productDao.findProductById(id));
您的产品可能为空。为了确定firstProduct,java必须在orElse方法中调用表达式,因此无论产品是否为null,您都必须确定在产品为空的情况下将返回的值。
为了确定secondProduct数据库,如果产品不为null,则不必查询,因为您传递的是仅当product为null时才会调用的供应商。
答案 2 :(得分:1)
另一个例子是当您接受供应商的方法不纯(即,它有副作用),并且在调用lambda之前发生副作用,并且lambda的行为受副作用影响。
例如,考虑这个例子:
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
的值,后者在lambda中使用(通过调用getField()
方法)。当lambda被调用到位时(即,当调用get()
时),在设置字段后调用getField()
将发生。换句话说,method()
接受Supplier<String>
而不是String
,试图让客户安全地调用getField()
方法。
当然,应尽可能避免副作用,这只是一个玩具示例,但它显示了供应商可以使用的潜在位置。
答案 3 :(得分:1)
供应商增加了一个间接层次。
鉴于"All problems in computer science can be solved by another level of indirection",可能存在一些可以通过使用供应商解决的问题。
然而,请注意结果&#34; ......除了间接层太多的问题。&#34;
所以,如果没有问题可以解决,那么供应商就会过度,你应该坚持直接调用 new 。
换句话说:不信任任何&#34;模式&#34;或者&#34;最佳实践&#34;这并不是从解释问题开始的(你的问题表明,你实际上是不信任,所以继续问这类问题)。
答案 4 :(得分:0)
我用它来避免不必要地创建其他状态:
private Supplier<Boolean> detach = () -> false;
private Supplier<Boolean> isAttached = () -> false;
private Supplier<Integer> index = () -> null;
private final Function<List<ObserverWrapper<X, Y>>, Boolean> attachFun = observers -> {
isAttached = () -> observers.contains(this);
detach = () -> observers.remove(this);
index = () -> observers.indexOf(this);
return observers.add(this);
};
public boolean attach(List<ObserverWrapper<X, Y>> observers) {
return attachFun.apply(observers);
}
public boolean isAttached() {
return isAttached.get();
}
public Integer observerIndex() {
return index.get();
}
有些人会说这本身是不必要的,但随后就变成了一个哲学问题。
如果计算机不存在,该问题将不存在,然后成为现实世界中的间接问题。
我可能承认供应商对我来说可能已经成瘾了,但在我看来,他们感觉就像是所有编程公理和原则的自然推论和扩展。
答案 5 :(得分:-1)
您可以在基于地图的工厂类
中使用供应商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()
,那么您将返回对同一对象的引用而不是新引用。