Immagina un codice come il seguente:
class Cache {
private Map<String, String> values = new HashMap<String, String>();
public String getFromCache(String key) {
if (!values.containsKey(key)) {
throw new NoEntryException();
}
return values.get(key);
}
public void setInCache(String key, String value) {
this.values.put(key, value);
}
}
class Foo {
private Cache cache = new Cache();
public String bla(String foo) {
try {
return cache.getFromCache(foo);
} catch (NoEntryException ex) {
String result = doSomeHeavyOperation(foo);
cache.setInCache(foo, result);
}
}
public String doSomeHeavyOperation(String something) {
// heavy operation
return something;
}
}
Questo è un caso d'uso valido per un'eccezione? Da un lato, potrebbe essere più lento a livello di calcolo lanciare l'eccezione, piuttosto che eseguire un metodo "cacheContains (String)" o verificare null (sebbene in tal caso null significhi "contains no element" o "always null for doSomeHeavyOperation"? ). D'altra parte influisce sul flusso di controllo, ma non sembra farlo in un modo che mi rende meno chiaro. Direi anche che per me sembra più pulito che controllare frontalmente usando un cacheContains (String).
I valori nella cache sono sempre gli stessi, per semplicità (anche se puoi aspettarti una invalidazione della cache dopo 30 minuti).
Ovviamente la cache usata qui è abbastanza semplice, ma in seguito sarà un wrapper attorno a un sistema più complicato, come un'integrazione Redis.
Modifica:
Ecco alcuni esempi di codice su come eseguire la risposta accettata in Java (è necessario un miglioramento con generici, più argomenti, ecc.):
abstract class MissingResultCaller {
abstract String doCall(String argument);
}
class Cache {
private Map<String, String> values = new HashMap<String, String>();
public String getFromCache(String key, MissingResultCaller missingResultCaller) {
if (!values.containsKey(key)) {
String value = missingResultCaller.doCall(key);
setInCache(key, value);
return value;
}
return values.get(key);
}
public void setInCache(String key, String value) {
this.values.put(key, value);
}
}
class Foo {
private Cache cache = new Cache();
public String bla(String foo) {
return cache.getFromCache(foo, new MissingResultCaller() {
@Override
String doCall(String argument) {
return doSomeHeavyOperation(argument);
}
});
}
public String doSomeHeavyOperation(String something) {
System.out.println("Did heavy operation");
return "heavy operation return";
}
}