/*
Copyright (C) 2007 Richard Gomes
This source code is release under the BSD License.
This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/
JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license. You should have received a
copy of the license along with this program; if not, please email
. The license is also available online at
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/
/*
Copyright (C) 2003 RiskMap srl
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license. You should have received a
copy of the license along with this program; if not, please email
. The license is also available online at
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
package org.jquantlib.util;
import java.util.List;
/**
* Framework for calculation on demand and result caching.
*
* @see Lazy Object Design Pattern
* @see Observer
* @see Observable
*
* @author Richard Gomes
*/
public abstract class LazyObject implements Observer, Observable {
//
// protected fields
//
protected boolean calculated;
protected boolean frozen;
//
// protected abstract methods
//
/**
* This method must implement any calculations which must be (re)done in order to calculate the desired results.
*
* @throws ArithmeticException
*
*/
protected abstract void performCalculations() throws ArithmeticException;
//
// public constructors
//
/**
* Creates a new LazyObject instance which is potentially able to perform calculations on demand every time it observes a change
* in a {@link Observable} object. A LazyObject is an {@link Observer} and an {@link Observable} at the same time.
*/
public LazyObject() {
this.calculated = false;
this.frozen = false;
}
//
// public final methods
//
/**
* This method force the recalculation of any results which would otherwise be cached.
*
* @note Explicit invocation of this method is not necessary if the object registered itself as observer with the
* structures on which such results depend. It is strongly advised to follow this policy when possible.
*/
public final void recalculate() {
final boolean wasFrozen = frozen;
calculated = frozen = false;
try {
calculate();
} finally {
frozen = wasFrozen;
notifyObservers();
}
}
/**
* This method constrains the object to return the presently cached results on successive invocations, even if arguments upon
* which they depend should change.
*/
public final void freeze() {
frozen = true;
}
/**
* This method reverts the effect of the freeze method, thus re-enabling recalculations.
*/
public final void unfreeze() {
frozen = false;
// send notification, just in case we lost any
notifyObservers();
}
//
// protected methods
//
/**
* This method performs all needed calculations by calling the performCalculations method.
*
*
* @note Objects cache the results of the previous calculation. Such results will be returned upon later invocations of calculate.
* When the results depend on arguments which could change between invocations, the lazy object must register itself as
* observer of such objects for the calculations to be performed again when they change.
*/
protected void calculate() {
if (!calculated && !frozen) {
// prevent infinite recursion in case of bootstrapping
calculated = true;
try {
performCalculations();
} catch (final ArithmeticException e) {
calculated = false;
throw e;
}
}
}
//
// implements Observer
//
// XXX:registerWith
// @Override
// public void registerWith(final Observable o) {
// o.addObserver(this);
// }
//
// @Override
// public void unregisterWith(final Observable o) {
// o.deleteObserver(this);
// }
@Override
//XXX::OBS public void update(final Observable o, final Object arg) {
public void update() {
// observers don't expect notifications from frozen objects
// LazyObject forwards notifications only once until it has been
// recalculated
if (!frozen && calculated)
//XXX::OBS notifyObservers(arg);
notifyObservers();
calculated = false;
}
//
// implements Observable
//
/**
* Implements multiple inheritance via delegate pattern to an inner class
*
* @see Observable
* @see DefaultObservable
*/
private final Observable delegatedObservable = new DefaultObservable(this);
@Override
public final void addObserver(final Observer observer) {
delegatedObservable.addObserver(observer);
}
@Override
public final int countObservers() {
return delegatedObservable.countObservers();
}
@Override
public final void deleteObserver(final Observer observer) {
delegatedObservable.deleteObserver(observer);
}
@Override
public final void notifyObservers() {
delegatedObservable.notifyObservers();
}
@Override
public final void notifyObservers(final Object arg) {
delegatedObservable.notifyObservers(arg);
}
@Override
public final void deleteObservers() {
delegatedObservable.deleteObservers();
}
@Override
public final List getObservers() {
return delegatedObservable.getObservers();
}
}
Ads help maintain this website.