Java 如何避免耦合两种方法,这两种方法现在具有类似的实现,但将来可能会发生变化?
我在一个类中有两个方法,它们目前共享一个非常相似的实现,但是这个实现在性能方面非常昂贵 样本:Java 如何避免耦合两种方法,这两种方法现在具有类似的实现,但将来可能会发生变化?,java,Java,我在一个类中有两个方法,它们目前共享一个非常相似的实现,但是这个实现在性能方面非常昂贵 样本: class Example { public void process(Object obj) { boolean someFact = getFirstFact(obj); boolean someOtherFact = getSecondFact(obj); //use the two facts somehow }
class Example
{
public void process(Object obj)
{
boolean someFact = getFirstFact(obj);
boolean someOtherFact = getSecondFact(obj);
//use the two facts somehow
}
public boolean getFirstFact(Object obj)
{
boolean data = someExpensiveMethod(obj);
//return some value derived from data
}
public boolean getSecondFact(Object obj)
{
boolean data = someExpensiveMethod(obj);
//return some other value derived from data
}
public boolean someExpensiveMethod(Object obj){...}
}
我曾想过以某种方式缓存某个ExpensiveMethod的结果,但这似乎是浪费,因为对象往往会进入、处理然后丢弃。它似乎也很笨拙——方法需要知道缓存,或者我需要在SSOMeeExpensiveMethod中缓存结果
即使是短期缓存也可能是坏消息,因为每天都有数百万个对象被处理
我的担忧有两个方面:第一,不能保证这两种方法始终依赖于第三种方法,因此任何解决方案都应该从其POV中透明,第二,显而易见的解决方案(在某些昂贵的方法中隐藏),就不需要长期保存的结果的空间而言,可能非常昂贵。您是否总是调用流程方法(我的意思是,您从不直接调用get…Fact方法)?如果是这种情况,那么您肯定知道getFirstFact总是在getSecondFact之前被调用 然后,您可以使用私有字段在getFirstFact方法中缓存someExpensiveMethod的布尔输出,并在getSecondFact方法中重用该值:
class Example
{
private boolean _expensiveMethodOutput;
public void process(Object obj)
{
boolean someFact = getFirstFact(obj);
boolean someOtherFact = getSecondFact(obj);
//use the two facts somehow
}
private boolean getFirstFact(Object obj)
{
_expensiveMethodOutput = someExpensiveMethod(obj);
//return some value derived from data
}
private boolean getSecondFact(Object obj)
{
boolean data = _expensiveMethodOutput;
//return some other value derived from data
}
private boolean someExpensiveMethod(Object obj){...}
}
从你的题目来看,我猜你不想这样做
class Example
{
public void process(Object obj)
{
boolean expensiveResult = someExpensiveMethod(obj);
boolean someFact = getFirstFact(expensiveResult);
boolean someOtherFact = getSecondFact(expensiveResult);
//use the two facts somehow
}
...
因为这意味着在更改其中一种方法时,您将无法再访问obj
。此外,您希望尽可能避免执行昂贵的方法。一个简单的解决办法是
private Object lastParam = null;
private boolean lastResult = false;
public boolean someExpensiveMethod(Object obj){
if (obj == lastParam) return lastResult;
lastResult = actualExpensiveMethod(obj);
lastParam = obj;
return lastResult ;
}
当然,这对多线程不起作用。(至少确保<代码>进程>代码>同步。)< p>我会考虑引入一个工厂方法和一个封装预处理的新对象。这样,一旦对象超出范围,jvm就可以丢弃预处理的数据
class PreprocessedObject {
private ... data;
public static PreprocessedObject create(Object obj) {
PreprocessedObject pObj = new PreprocessedObject();
// do expensive stuff
pObj.data = ...
return pObj;
}
public boolean getFirstFact() {
//return some value derived from data
}
public boolean getSecondFact() {
//return some other value derived from data
}
}
我曾考虑过以某种方式缓存someExpensiveMethod
的结果,但这似乎是浪费,因为对象往往会进入、处理然后丢弃
我不认为这是浪费。缓存基本上就是这样工作的。您将进入的对象与最近处理的对象进行比较,当您得到“命中”时,您可以避免调用someExpensiveMethod
的开销
缓存是否真正适用于您的应用程序将取决于许多因素,如:
- 可以保留在缓存中的对象/结果对的数量
- “命中”的概率
- 执行缓存探测的平均成本(在“命中”和“未命中”情况下)
- 调用
someExpensiveMethod
- 维护缓存的直接成本;e、 g.如果您使用LRU或其他一些策略来清除没有帮助的缓存项,以及
- 维护缓存的间接成本
someExpensiveMethod
中缓存结果
在我看来,这两种方式都不“笨重”。这是实现缓存的方式
即使是短期缓存也可能是坏消息,因为每天都有数百万个对象被处理
再说一遍,我看不出你论点的逻辑。如果每天处理数以百万计的对象,而你保持(比如)最后5分钟的价值,那么只需要缓存数万个对象。这绝非“坏消息”
如果您真的每天处理“数以百万计”的对象,那么:
一些昂贵的方法不可能那么昂贵。。。除非您拥有高效缓存和大量内存,或者拥有大量处理器,或者两者兼而有之
- 您对优雅(不简洁)和避免耦合的关注必须是设计应用程序以使其跟上的次要问题,并且
- 您可能需要在多处理器上运行,因此需要处理缓存可能成为并发瓶颈的事实
- 除了斯蒂芬的答案,我建议你看看谷歌番石榴。有一个计算地图的概念,适合您在这里面临的问题。我写了一篇关于这方面的文章
就代码而言,我建议如下:
class Example {
private ConcurrentMap<Object, Boolean> cache;
void initCache() {
cache = new MapMaker().softValues()
.makeComputingMap(new Function<Object, Boolean>() {
@Override
public Boolean apply(Object from) {
return someExpensiveMethod(from);
}
});
}
public void process(Object obj) {
boolean someFact = getFirstFact(obj);
boolean someOtherFact = getSecondFact(obj);
// use the two facts somehow
}
public boolean getFirstFact(Object obj) {
boolean data = cache.get(obj);
// return some value derived from data
}
public boolean getSecondFact(Object obj) {
boolean data = cache.get(obj);
// return some other value derived from data
}
public boolean someExpensiveMethod(Object obj) {
}
}
类示例{
私有ConcurrentMap缓存;
void initCache(){
cache=新的MapMaker().softValues()
.makeComputingMap(新函数(){
@凌驾
公共布尔应用(对象来自){
返回一些ExpensiveMethod(从);
}
});
}
公共作废流程(对象obj){
布尔someFact=getFirstFact(obj);
布尔someOtherFact=getSecondFact(obj);
//以某种方式使用这两个事实
}
公共布尔getFirstFact(对象obj){
布尔数据=cache.get(obj);
//返回从数据中派生的一些值
}
公共布尔getSecondFact(对象obj){
布尔数据=cache.get(obj);
//返回从数据派生的其他值
}
公共布尔someExpensiveMethod(对象obj){
}
}
标题与问题不符-您是否担心耦合问题,还是希望找到一种缓存结果的好方法