我正在阅读如何在阅读和应用this answer之后实例化一个通用的;我想知道期待Supplier<T>
与期待新T
实例之间的区别是什么。
示例:
abstract class AbstractService<T extends AbstractEntity> {
protected Supplier<T> makeNewThing(); // supplier is expected
public T myMethod(){
T object = makeNewThing().get(); // local object by calling supplier
object.doStuff();
return object;
}
}
class CarService extends AbstractService<Car> {
public Supplier<Car> makeNewThing(){
return Car::new;
}
}
VS
abstract class AbstractService<T extends SomeAbstractEntity> {
protected T makeNewThing(); // object is expected, newness is assumed
public T myMethod(){
T object = makeNewThing(); // local object by calling constructor
object.doStuff();
return object;
}
}
class CarService extends AbstractService<Car> {
public Car makeNewThing(){
return new Car();
}
}
我唯一能想到的是期望供应商确保创建一个新对象,但是当期望一个对象时,我们只能假设实现类正在调用构造函数而不是重用现有实例。
我想知道其他客观差异和可能的用例,如果有的话。提前谢谢。
答案 0 :(得分:9)
使用 protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidUserAuthorization requirement)
{
List<KeyValuePair<string, string>> parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("UserAlias", context.User.Identity.Name.Split('@')[0])
};
var isAuthorized = this.CubeServiceManager.GetDataFromService("CheckIfAuthorized", "GET", this.ConnectionStrings.BaseAddress, parameters);
if (isAuthorized == "true")
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
推迟创建实例。
这意味着您可以避免创建不必要的实例。
例如,假设您将Supplier
的输出传递给某个方法。
makeNewThing()
调用第一个变体需要创建一个T实例,即使您不打算使用它。
调用第二个变体只在必要时创建一个T实例。
使用public void makeNewThingSometimes (T newInstance)
{
if (someCondition) {
this.instance = newInstance;
}
}
public void makeNewThingSometimes (Supplier<T> supplier)
{
if (someCondition) {
this.instance = supplier.get();
}
}
可以节省存储空间(如果创建实例需要大量内存)和时间(如果构造函数的执行是扩展的)。
答案 1 :(得分:4)
我唯一能想到的是期望供应商确保 将创建一个新对象,
不一定
您以这种方式实施Supplier
:
return SomeEntityImplementation::new;
但你可以用其他方式实现它:
if (myCachedObject != null){
return (()-> myCachedObject);
}
return SomeEntityImplementation::new;
这两种方式都可用于返回缓存对象或创建新对象。
Supplier
优势之一是Supplier
创建对象的情况:实际上只有在调用Supplier.get()
方法时才创建此对象。
请注意,在您的示例中,使用Supplier
并没有带来任何好处,因为在两种情况下(有或没有Supplier
),对象创建已经以惰性方式执行:作为工厂方法被调用。
要利用它,您应该有一个方法,提供{E}和Dasblinkenlight示例中的Supplier<T>
参数。
另一个Supplier
优势是它能够实现可能返回多项内容的工厂
使用Supplier
允许使用更短且更易读的代码,此外不依赖于Java Reflection。
假设您想要从Enum
值创建对象,您可以这样写:
public enum MyBaseClassFactory {
ENUM_A (A::new),
ENUM_B (B::new),
ENUM_C (C::new),
ENUM_D (D::new);
private Supplier<BaseClass> supplier;
MyBaseClassFactory (Supplier<BaseClass> supplier){
this.supplier = supplier;
}
public BaseClass createObject(){
return supplier.get();
}
}
你可以这样使用它:
BaseClass base = MyBaseClassFactory.ENUM_A.createObject();
如果没有Supplier
,则必须使用Reflection(可能在运行时失败)或编写冗长且不可维护的代码。
例如使用Reflection:
public enum MyEnumFactoryClass {
ENUM_A(A.class), ENUM_B(B.class), ENUM_C(C.class), ENUM_D(D.class);
private Class<BaseClass> clazz;
MyEnumFactoryClass(Class<BaseClass> clazz) {
this.clazz = clazz;
}
public BaseClass createObject() {
return clazz.newInstance();
}
}
例如没有反射但代码更详细:
public enum MyEnumFactoryClass {
ENUM_A {
@Override
public BaseClass createObject() {
return new A();
}
},
ENUM_B {
@Override
public BaseClass createObject() {
return new B();
}
},
ENUM_C {
@Override
public BaseClass createObject() {
return new C();
}
},
ENUM_D {
@Override
public BaseClass createObject() {
return new D();
}
};
public abstract BaseClass createObject();
}
当然,您可以通过Supplier
与Map<String, Supplier<BaseClass>>
一起使用{{1}}。{/ p>
答案 2 :(得分:3)
第一个解决方案更灵活,因为在对象创建中额外的间接级别允许类库的用户独立于ServiceImpl<SomeEntityImplementation>
类更改新项目的来源。
您可以在不进行子类化或重新编译Supplier<T>
的情况下创建新的ServiceImpl
实例,因为存在额外的间接级别。 ServiceImpl
可以按如下方式实施:
class ServiceImpl<SomeEntityImplementation> {
private final Supplier<SomeEntityImplementation> supplier;
public Supplier<T> makeNewThing(){
return supplier;
}
public ServiceImpl(Supplier<SomeEntityImplementation> s) {
supplier = s;
}
}
这使得ServiceImpl
的用户可以提供他们自己的Supplier<T>
,这是使用第二种方法无法实现的,其中新项目的来源被合并到服务本身的实现中。