Java 在惰性初始化和一般情况下,重写可以有效地替代if语句吗?
我试图模拟下面的抽象类,设计为只启用一个延迟初始化,而不使用逻辑语句。为了简单起见,我忽略了线程安全所必需的同步元素Java 在惰性初始化和一般情况下,重写可以有效地替代if语句吗?,java,design-patterns,inheritance,overriding,oop,Java,Design Patterns,Inheritance,Overriding,Oop,我试图模拟下面的抽象类,设计为只启用一个延迟初始化,而不使用逻辑语句。为了简单起见,我忽略了线程安全所必需的同步元素 abstract class Thunk<T> { private boolean initiated = false; private T value; public T get() { if(!initiated) // not using (value == null) {
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
抽象类Thunk
{
私有布尔值=false;
私人T值;
公共部门得不到
{
如果(!initiated)//未使用(值==null)
{
值=计算();
启动=真;
}
返回值;
}
抽象保护T compute();
}
以下抽象类的实例是否可以被子类黑客攻击以多次初始化同一变量
abstract class Thunk<T>
{
private T value;
private Computer<T> computer;
public Thunk()
{
computer = new Computer<T>(this);
}
public T get()
{
value = computer.getValue();
return value;
}
abstract protected T compute();
private class Computer<T>
{
private static final String TAG = "Computer";
private Thunk<T> thunk;
private T value;
private Computer<T> computer;
public Computer(Thunk<T> thunk)
{
Log.d(TAG, "constructed");
this.thunk = thunk;
computer = this;
}
public T getValue()
{
Log.d(TAG + ".getValue()", "");
value = computer.computeValue();
return value;
}
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
value = thunk.compute();
computer = new DumbComputer<T>(thunk, value);
return value;
}
//this is for maximal encapsulation
private class DumbComputer<T> extends Computer<T>
{
private static final String TAG = "DumbComputer";
private T value;
public DumbComputer(Thunk<T> thunk, T value)
{
super(thunk);
Log.d(TAG + ".contructed()", "booki");
this.value = value;
}
//overriding so that value will be calculated only once.
@Override
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
return value;
}
}
}
}
抽象类Thunk
{
私人T值;
专用计算机;
公共Thunk()
{
计算机=新计算机(此);
}
公共部门得不到
{
value=computer.getValue();
返回值;
}
抽象保护T compute();
专用计算机
{
私有静态最终字符串标记=“计算机”;
私人扑通扑通;
私人T值;
专用计算机;
公共计算机(Thunk-Thunk)
{
日志d(标签“已建造”);
this.thunk=thunk;
计算机=这个;
}
公共T getValue()
{
Log.d(标记+”.getValue()“,”);
value=computer.computeValue();
返回值;
}
受保护的T计算值()
{
Log.d(标记+“.computeValue()”,“”);
value=thunk.compute();
计算机=新计算机(thunk,值);
返回值;
}
//这是为了最大限度地封装
私有类计算机扩展计算机
{
私有静态最终字符串标记=“DumbComputer”;
私人T值;
公用计算机(Thunk-Thunk,T值)
{
超级(thunk);
Log.d(TAG+“.constructed()”,“booki”);
这个值=值;
}
//重写,以便仅计算一次值。
@凌驾
受保护的T计算值()
{
Log.d(标记+“.computeValue()”,“”);
返回值;
}
}
}
}
您的第二个示例(可能)没有达到预期效果,因为您每次调用Thunk.get
时都会创建一台新的DumbComputer
。您可以实现以下目标(但我认为这不是一个好的设计,我真的不认为与更简单的解决方案相比有什么优势):
抽象类Thunk{
T值;
计算机;
受保护的抽象T doCompute();
专用接口计算机{
计算机getComputer();
T计算();
}
公投(){
//用计算机初始化计算机
计算机=新计算机(){
计算机getComputer(){
//退回一台哑计算机
返回新计算机(){
计算机getComputer(){返回此;}
T compute(){返回值;}
}
}
T compute(){value=doCompute();返回值;}
};
}
公共T getValue(){
tv=computer.compute();computer=computer.getComputer();返回v;
}
}
是,通过重写get
方法
要解决此问题,可以将get
转换为final
方法。这将防止重写并提供类似于单例的行为
请注意,您编写的代码不是线程安全的
通过使方法同步化
(在你知道你给出了一个问题并且该方法是热点之前,不要担心性能,因为慢正确的代码比快错误的代码好,JVM非常擅长优化锁。如果你发现这个类的某个特定锁太热,你可以使用一些技巧来加速它……但是不要担心这个问题(现在还没有)
还值得指出的是,如果您想要最好的单例惰性init,那么可以使用lazy init的资源持有者内部类模式(不适用于这个类需要的用例。它只用于单例)
更新(以评论不支持格式响应评论)
这样做:
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public synchronized final T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
抽象类Thunk
{
私有布尔值=false;
私人T值;
公共同步最终无法获取()
{
如果(!initiated)//未使用(值==null)
{
值=计算();
启动=真;
}
返回值;
}
抽象保护T compute();
}
这是可能工作的最简单的代码。不要梦想尝试“改进”该代码。它可以改进,但改进会因类的使用方式而有所不同,改进的复杂性会隐藏代码试图做的事情。从最简单的可以工作的事情开始,然后继续
保持简单愚蠢
不要解决你还没有解决的问题
public final void f() {
...
X x = ...;
g(x);
...
}
abstract protected void g(X x);
在合同编程中非常有用:
- 施加行为(主体为f),以及
- 提供本地上下文(x)
启动的)。
因此,是的,这对于延迟评估是很好的。虽然延迟评估可以在字段级别实现,例如通过很少见到的jewelFuture
实现,但实际上不清楚您在问什么。也许可以在代码之外写一个问题的摘要。我可以选择仅同步(锁定)原始computeValue()的内容吗方法,以保存synchr
public final void f() {
...
X x = ...;
g(x);
...
}
abstract protected void g(X x);