Subclassing HashBasedTable from guava collection - java

I have a multilevel map requirement and I am using Guava Table . More precisely HashBasedTable.
Since my code needs a lot of custom processing on this dataset I would like to implement a derived class e.g. EventActionRuleTable which holds a map of Event - Action objects against a source.
something like this
HashMap<Source , Map<Event, Action> ruleMap ;
I am replacing the above with a
Table<Source, Event , Action> ruleTable = HashBasedTable.create();
But to hold all my custom code I would like to subclass HashBasedTable and figured its simply not possible.
Thus I choose to go with a delegate i.e.
public EventActionRule extends Table<Source, Event, Action>{
private HashBasedTable<Source, Event, Action> backup = null ;
public HashBasedTable<Source, Event, Action> getBackupTable() {
if (backupTable == null) {
backupTable = HashBasedTable.create() ;
}
return backupTable;
}
#Override
public boolean isEmpty() {
return getBackupTable().isEmpty();
}
/**
All other methods of Table interface overridden to delegate calls to backup instance
*/
....
}
Is this approach correct ? Can you list issues if its not ? Any alternative approach ?
Is HashBasedTable Gwt serialization compatible ? I am asking since the two backup maps used internally in the HashBasedTable are annotated with #GwtTransient annotation.

Ad 1. Your approach is correct, although you can use built-in Guava solution for using delegates - Forwarding Decorators:
For all the various collection interfaces, Guava provides Forwarding abstract classes to simplify using the decorator pattern.
In your case, ForwardingTable is waiting for you:
public static class EventActionRule extends ForwardingTable<Source, Event, Action> {
private Table<Source, Event, Action> delegate = HashBasedTable.create();
#Override
protected Table<Source, Event, Action> delegate() {
return delegate;
}
// just an example: isEmpty (and other methods) is ready to be overriden
#Override
public boolean isEmpty() {
boolean isEmpty = delegate().isEmpty();
System.out.println("Was map empty? " + isEmpty);
return isEmpty;
}
}
Ad. 2. Yes, HashBasedTable is serializable under GWT.

Related

Design generic interface for data object used throughout a service

Been migrating over some legacy code and I came across this.
#Getter
#Setter
public class CollectedData
{
SkillResponse skills;
TrendingResponse storyMatch;
Map<String, String> slotData;
Map<String, String> slotDataSecondSource;
Boolean hasSlots;
Boolean hasSlotsSecondSource;
KnowledgeRequest request;
}
Since I've been using java 8 and accustomed to streams, I started to restructure this response class as ..
#Getter
#Setter
public class CollectedData
{
List<DataSupplierResponse> dataSupplierResponses;
Metadata metadata;
}
Where DataSupplierResponse was to be a defined interface like so..
public interface DataSupplierResponse<T>
{
DataSupplierType getDataSupplierType();
T getSupplierResponse();
}
Implementation Example:
public class DataSupplierResponseImpl implements DataSupplierResponse<TrendingResponse>
{
private TrendingResponse mTrendingResponse;
public DataSupplierResponseImpl(
TrendingResponse trendingResponse)
{
mTrendingResponse = trendingResponse;
}
#Override
public DataSupplierType getDataSupplierType()
{
return DataSupplierType.TRENDING_STORY;
}
#Override
public TrendingResponse getSupplierResponse()
{
return mTrendingResponse;
}
}
The goal is to run certain predicates depending on the CollectedData.
Optional<DataSupplierResponse> first = data.getDataSupplierResponses().stream()
.filter(res -> res.getDataSupplierType().equals(DataSupplierType.TRENDING_STORY))
.findFirst();
This would need a cast in order to get the right object. It returns Object
TrendingResponse match = first.get().getSupplierResponse();
Thus when I started refactoring, I assumed to solve this issue of data being available by creating the generic interface that returns different data. To make this code work, I would have to cast the return object of getSupplierResponse which defeats the purpose of using generics. I need to make this Data Carrier object as clean and beautiful as possible for my own sake. Any ideas how I should structure these classes, and/or how to use generics to solve this problem.
EDIT: I know the StackOverflow community likes to enforce objective, concrete answers but where else to go to for design questions?
You have to specify the List in CollectedData also with generics. E.g:
List<DataSupplierResponse> dataSupplierResponse;
should actually be:
List<DataSupplierResponse<YourType>> dataSupplierResponse;
where YourType corresponds to the type of the response. That is because when using a RawType (a generic class without actually specifiying a generic) all Generic information for that class is eliminated. That's why it is returning Objects and you have to manually cast it.
Unless used in other places, I'd get rid of the enumeration type DataSupplierType as the classes TrendingResponse (and others) already provide a discrimination criteria.
(Also keep in mind that enums are full classes)
The perfect response to this would have you implement a basic type for your response, e.g:
interface Response {
int getScore(); // implement in subclasses
String getName(); // implement in subclasses
}
class TrendingResponse implements Response {}
class SkillResponse implements Response {}
class OtherResponse implements Response {}
but this is not strictly necessary.
At this point just a generic wrapper class would be enough (no need to have a base interface and extend it for each type of response):
class DataSupplierResponse<T extends Response> {
private T t;
public DataSupplierResponse(final T t) {
this.t = t;
}
public T getSupplierResponse() {
return this.t;
}
}
This would allow you to call:
Optional<DataSupplierResponse<?>> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.findFirst();
first.ifPresent( o -> o.getSupplierResponse().getScore() );
or simply
Optional<?> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.map(r -> r::getSupplierResponse)
.findFirst();
Even without the base interface Response (which is useful only for defining common behavior in your responses), your class DataSupplierResponse<T> wouldn't need the enumeration type.

How to log List interface method for existing code

I have existing codebase that sometimes uses ArrayList or LinkedList and I need to find a way to log whenever add or remove is called to track what has been either added or removed.
What is the best way to make sure I have logging in place?
So for example.
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
and
LinkedList<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList.add(333);
Not sure if I can intercept add method to achieve this or create overriding class that implements java.util.List interface then use it instead. Either way I'm looking for a good solution that requires minimum intervention and prefrerrably without using any third party packages...
I would use the so called Decorator Pattern to wrap your lists.
This would be a simple example code just to give you an idea:
private static class LogDecorator<T> implements Collection<T> {
private final Collection<T> delegate;
private LogDecorator(Collection<T> delegate) {this.delegate = delegate;}
#Override
public int size() {
return delegate.size();
}
#Override
public boolean isEmpty() {
return delegate.isEmpty();
}
#Override
public boolean contains(Object o) {
return delegate.contains(o);
}
#Override
public Iterator<T> iterator() {
return delegate.iterator();
}
#Override
public Object[] toArray() {
return delegate.toArray();
}
#Override
public <T1> T1[] toArray(T1[] a) {
return delegate.toArray(a);
}
#Override
public boolean add(T t) {
// ADD YOUR INTERCEPTING CODE HERE
return delegate.add(t);
}
#Override
public boolean remove(Object o) {
return delegate.remove(o);
}
#Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
#Override
public boolean addAll(Collection<? extends T> c) {
return delegate.addAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
#Override
public void clear() {
delegate.clear();
}
}
There is not really a simple way to get there.
Those classes are part of the "standard libraries"; so you can't change their behavior. You could create your own versions of them; and use class path ordering to get them used; but this really dirty hack.
The only other option: extend those classes; #Override the methods you want to be logged; and make sure all your sources use your own versions of those classes. Or if you prefer composition over inheritance you go for the decorator pattern; as suggested by JDC's answer.
The "third" option is really different - you turn to aspect oriented programming (for example using AspectJ) and use such tools to manipulate things on a bytecode level. But that adds a whole new layer of "complexity" to your product; thus I am not counting it as real option.
EDIT on your answer: it seems that you don't understand the difference between interface and implementation?! An interface simply describes a set of method signatures; but in order to have real code behind those methods, there needs to be an implementing class. You see, when you do
List<X> things = new ArrayList<>();
the real type of things is ArrayList; but you rarely care about that real type; it is good enough to know that you can all those List methods on things. So, when you create some new implementation of the List interface ... that doesn't affect any existing
... = new ArrayList ...
declarations at all. You would have to change all assignments to
List<X> things = new YourNewListImplementation<>();
JDC has given a good way to follow.
I would like bring important precisions.
The decorator pattern allows to create a class which decorates another class by adding or removing dynamically a new responsibility to an instance.
In your case, you want to add responsibility.
Decorator is not an intrusive pattern but the decorator class have to conform to the class that it decorates.
So in your case, having a decorator which derives from the Collection interface is not conform to the decorated object since List has methods that Collection has not.
Your need is decorating List instances, so decorator should derive from the List type.
Besides, the decorator class can do, according its needs, a processing before and or after the operation of the class that it decorates but it is also responsible to call the original operation of the decorated class.
In your case, you want to know if an element was added or in or removed from the List. To achieve it, as the method result has consequences on whether you log or not the information, it is preferable to delegate first the processing to the decorated object and then your decorator can perform its processings.
Sometimes, you don't need to decorate a method, don't do it but don't forget to delegate suitably to the decorated object.
import java.util.Iterator;
import java.util.List;
public class DecoratorList<T> implements List<T> {
private static final Tracer tracer = ....;
private List<T> decorated;
private DecoratorList(List<T> decorated) {
this.decorated=decorated;
}
// no decorated methods
....
#Override
public int size() {
return this.decorated.size();
}
#Override
public boolean isEmpty() {
return this.decorated.isEmpty();
}
#Override
public boolean contains(Object o) {
return this.decorated.contains(o);
}
#Override
public Iterator<T> iterator() {
return this.decorated.iterator();
}
....
// end no decorated methods
// exemple of decorated methods
#Override
public void add(int index, T element) {
tracer.info("element " + element + " added to index " + index);
this.decorated.add(index,element);
}
#Override
public boolean remove(Object o) {
final boolean isRemoved = this.decorated.remove(o);
if (isRemoved){
tracer.info("element " + o + " removed");
}
return isRemoved;
}
}
As explained, a decorator is not intrusive for the decorated objects.
So the idea is not changing your code that works but add the decorating operation just after the list be instantiated.
If don't program by interface when you declare your list variables, that is you declare ArrayList list = new ArrayList() instead of List list = new ArrayList() , of course you should change the declared type to List but it doesn't break the code, on the contrary.
Here is your example code :
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
LinkedList<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList.add(333);
Now, you could do it :
List<Integer> list = new ArrayList<Integer>();
list = new DecoratorList<Integer>(list); // line added
list.add(123);
List<Integer> anotherNewList = new LinkedList<Integer>();
anotherNewList = new DecoratorList<Integer>(anotherNewList); // line added
anotherNewList.add(333);
To ease the task and make it safer, you could even create a util method to apply the decoration on the list :
private static <T> List<T> decorateList(List<T> list) {
list = new DecoratorList<T>(list);
return list;
}
and call it like that :
List<Integer> list = new ArrayList<Integer>();
list = decorateList(list); // line added
list.add(123);
You can use Aspects - but it will log every add and remove call:
#Aspect
public class ListLoggerAspect {
#Around("execution(* java.util.List.add(..))")
public boolean aroundAdd(ProceedingJoinPoint joinPoint) throws Throwable {
boolean result = (boolean) joinPoint.proceed(joinPoint.getArgs());
// do the logging
return result;
}
}
You'll need to configure the aspect in META-INF/aop.xml :
<aspectj>
<aspects>
<aspect name="com.example.ListLoggerAspect"/>
</aspects>
</aspectj>
An easy way to accomplish this is wrapping your source list in a ObservableList and use that as base list. You can simply add an listener to this list to catch every modification (and log out if you wish)
Example:
List obs = FXCollections.observableList(myOriginalList);
obs.addListener(c -> {
for(Item it : c.getRemoved())
System.out.println(it);
for(Item it : c.getAddedSubList())
System.out.println(it);
});
See the javafx documentation on how to add a good listener
Your List is the source here. You need to keep track of the changes to the source. This is a good and natural example of the Observer pattern. You can create an Observable which is your list. Then create some Observers and register them to the Observable. When the Observable is changed, notify all the registered Observers. Inside the Observer you can log the changes using the input event. You should literally implement some ObservableCollection here. You can use Java Rx to get this work done. Please find the sample code given below.
package com.test;
import java.util.ArrayList;
import java.util.List;
import rx.Observable;
import rx.subjects.PublishSubject;
public class ObservableListDemo {
public static class ObservableList<T> {
protected final List<T> list;
protected final PublishSubject<T> onAdd;
public ObservableList() {
this.list = new ArrayList<T>();
this.onAdd = PublishSubject.create();
}
public void add(T value) {
list.add(value);
onAdd.onNext(value);
}
public Observable<T> getObservable() {
return onAdd;
}
}
public static void main(String[] args) throws InterruptedException {
ObservableList<Integer> observableList = new ObservableList<>();
observableList.getObservable().subscribe(System.out::println);
observableList.add(1);
Thread.sleep(1000);
observableList.add(2);
Thread.sleep(1000);
observableList.add(3);
}
}
Hope this helps. Happy coding !
We need a little more information to find the right solution. But I see a number of options.
You can track changes, using a decorator.
You can copy the collection and calculate the changes
You can use aspects to 'decorate' every List in the JVM
Change the existing codebase (a little bit)
1) works if you know exactly how the list is used, and once it is returned to your new code, you are the only user. So the existing code can't have any methods that add to the original list (because would invoke add/remove on the delegate instead of the decorated collection).
2) This approach is used when multiple classes can modify the list. You need to be able to get a copy of the list, before any modifications begin, and then calculate what happened afterwards. If you have access to Apache Collections library you can use CollectionUtils to calculate the intersection and disjunction.
3) This solution requires some for of weaving (compile or load time) as this will create a proxy for every List, so it can add callback code around the method calls. I would not recommend this option unless you have a good understanding of how aspects work, as this solution has a rather steep learning curve, and if something goes wrong and you need to debug you code, it can be a bit tricky.
4) You say existing codebase, which leads me to believe, that you could actually change the code if you really wanted. If this is at all possible, that is the approach I would choose. If the user of the List needs to be able to track changes, then the best possible solution is that the library returns a ChangeTrackingList (interface defining methods from tracking), which you could build using decoration.
One thing you have to be aware of when decorating, is that List has a removeAll() and a addAll(), these methods may or may not call the add() and remove(), this depends on the list implementation. If you are not aware of how these methods are invoked internally you could end up seeing an object as removed twice (unless you can use a set).

is this java interface tactic sound?

I've been thinking about implementing a certain tactic for my code.
This is my setup:
I've got an interface called "Object".
Then I've got an interface called "Entity" that extends "Object".
From entity then springs countless implementations, like "army", "city", "lemon", etc.
Now, I want to gather all of these Objects into some form of map. Then from that map I want to get the particular implementation of "Object".
My thought out solution for this is as follows:
Object has method :
public Entity getEntity()
All implementations of Object returns null, while Entity returns itself.
Likewise, in entity I'd have:
public Army getArmy()
public City getCity()
That way, I can simply pull an object from the map and get the specific class from it with a series of null checks, like so;
Object o = Objects.getObject(2dCoordinates);
Entity e = o.getEntity();
if (e != null){
Army a = e.getArmy();
if (a != null)
a.armySpecificMethod();
}
All without using "instanceof" and casting, which I hate.
The question is whether there's some unforeseen problem about this? I'd rather learn from someone that knows before refactoring my code and find out for myself.
You asked if there are any pitfalls to your strategy. I would say no, since C# uses the same strategy with their as keyword. Example: e as Army would return e if e is-a Army, or null otherwise. It is basicly a cast that instead of failing returns null.
However you don't have to implement this functionality using interfaces, you can write your own as method for example like this:
static <T> T as(Class<T> clazz, Object obj) {
if (clazz.isInstance(obj)) {
return (T) obj;
}
return null;
}
usage:
Object o = Objects.getObject(2dCoordinates);
Entity e = as(Entity.class, o);
if (e != null) {
Army a = as(Army.class, e);
if (a != null)
a.armySpecificMethod();
}
Another approach would be to register callbacks/strategies to be invoked on particular events. Something like that:
public interface OnMapClicked<T> {
void onItemSelected(T item);
}
And your GameMap (or whatever) implementation would be:
public GameMap {
private final Map<Class<?>, OnMapClicked> listeners = new HashMap<>();
public <T> void registerListener(Class<? extends T> type, OnMapClicked<T> listener) {
listeners.put(type, listener);
}
//
private void onMapClicked(Coordinates coordinates) {
Object object = findObject(coordinates);
listeners.get(object.getClass()).onItemSelected(object);
}
}
That's very rough untested implementation, but hopefully you got the idea. There is one usage of non-generic instance here (in onMapClicked), but it should be safe, since we're checking the input type in registerListener.

Using enum to implement multitons in Java

I would like to have a limited fixed catalogue of instances of a certain complex interface. The standard multiton pattern has some nice features such as lazy instantiation. However it relies on a key such as a String which seems quite error prone and fragile.
I'd like a pattern that uses enum. They have lots of great features and are robust. I've tried to find a standard design pattern for this but have drawn a blank. So I've come up with my own but I'm not terribly happy with it.
The pattern I'm using is as follows (the interface is highly simplified here to make it readable):
interface Complex {
void method();
}
enum ComplexItem implements Complex {
ITEM1 {
protected Complex makeInstance() { return new Complex() { ... }
},
ITEM2 {
protected Complex makeInstance() { return new Complex() { ... }
};
private Complex instance = null;
private Complex getInstance() {
if (instance == null) {
instance = makeInstance();
}
return instance;
}
protected void makeInstance() {
}
void method {
getInstance().method();
}
}
This pattern has some very nice features to it:
the enum implements the interface which makes its usage pretty natural: ComplexItem.ITEM1.method();
Lazy instantiation: if the construction is costly (my use case involves reading files), it only occurs if it's required.
Having said that it seems horribly complex and 'hacky' for such a simple requirement and overrides enum methods in a way which I'm not sure the language designers intended.
It also has another significant disadvantage. In my use case I'd like the interface to extend Comparable. Unfortunately this then clashes with the enum implementation of Comparable and makes the code uncompilable.
One alternative I considered was having a standard enum and then a separate class that maps the enum to an implementation of the interface (using the standard multiton pattern). That works but the enum no longer implements the interface which seems to me to not be a natural reflection of the intention. It also separates the implementation of the interface from the enum items which seems to be poor encapsulation.
Another alternative is to have the enum constructor implement the interface (i.e. in the pattern above remove the need for the 'makeInstance' method). While this works it removes the advantage of only running the constructors if required). It also doesn't resolve the issue with extending Comparable.
So my question is: can anyone think of a more elegant way to do this?
In response to comments I'll tried to specify the specific problem I'm trying to solve first generically and then through an example.
There are a fixed set of objects that implement a given interface
The objects are stateless: they are used to encapsulate behaviour only
Only a subset of the objects will be used each time the code is executed (depending on user input)
Creating these objects is expensive: it should only be done once and only if required
The objects share a lot behaviour
This could be implemented with separate singleton classes for each object using separate classes or superclasses for shared behaviour. This seems unnecessarily complex.
Now an example. A system calculates several different taxes in a set of regions each of which has their own algorithm for calculting the taxes. The set of regions is expected to never change but the regional algorithms will change regularly. The specific regional rates must be loaded at run time via remote service which is slow and expensive. Each time the system is invoked it will be given a different set of regions to calculate so it should only load the rates of the regions requested.
So:
interface TaxCalculation {
float calculateSalesTax(SaleData data);
float calculateLandTax(LandData data);
....
}
enum TaxRegion implements TaxCalculation {
NORTH, NORTH_EAST, SOUTH, EAST, WEST, CENTRAL .... ;
private loadRegionalDataFromRemoteServer() { .... }
}
Recommended background reading: Mixing-in an Enum
Seems fine. I would make initialization threadsafe like this:
enum ComplexItem implements Complex {
ITEM1 {
protected Complex makeInstance() {
return new Complex() { public void method() { }};
}
},
ITEM2 {
protected Complex makeInstance() {
return new Complex() { public void method() { }}
};
private volatile Complex instance;
private Complex getInstance() {
if (instance == null) {
createInstance();
}
return instance;
}
protected abstract Complex makeInstance();
protected synchronized void createInstance() {
if (instance == null) {
instance = makeInstance();
}
}
public void method() {
getInstance().method();
}
}
The modifier synchronized only appears on the createInstance() method, but wraps the call to makeInstance() - conveying threadsafety without putting a bottleneck on calls to getInstance() and without the programmer having to remember to add synchronized to each to makeInstance() implementation.
This works for me - it's thread-safe and generic. The enum must implement the Creator interface but that is easy - as demonstrated by the sample usage at the end.
This solution breaks the binding you have imposed where it is the enum that is the stored object. Here I only use the enum as a factory to create the object - in this way I can store any type of object and even have each enum create a different type of object (which was my aim).
This uses a common mechanism for thread-safety and lazy instantiation using ConcurrentMap of FutureTask.
There is a small overhead of holding on to the FutureTask for the lifetime of the program but that could be improved with a little tweaking.
/**
* A Multiton where the keys are an enum and each key can create its own value.
*
* The create method of the key enum is guaranteed to only be called once.
*
* Probably worth making your Multiton static to avoid duplication.
*
* #param <K> - The enum that is the key in the map and also does the creation.
*/
public class Multiton<K extends Enum<K> & Multiton.Creator> {
// The map to the future.
private final ConcurrentMap<K, Future<Object>> multitons = new ConcurrentHashMap<K, Future<Object>>();
// The enums must create
public interface Creator {
public abstract Object create();
}
// The getter.
public <V> V get(final K key, Class<V> type) {
// Has it run yet?
Future<Object> f = multitons.get(key);
if (f == null) {
// No! Make the task that runs it.
FutureTask<Object> ft = new FutureTask<Object>(
new Callable() {
public Object call() throws Exception {
// Only do the create when called to do so.
return key.create();
}
});
// Only put if not there.
f = multitons.putIfAbsent(key, ft);
if (f == null) {
// We replaced null so we successfully put. We were first!
f = ft;
// Initiate the task.
ft.run();
}
}
try {
/**
* If code gets here and hangs due to f.status = 0 (FutureTask.NEW)
* then you are trying to get from your Multiton in your creator.
*
* Cannot check for that without unnecessarily complex code.
*
* Perhaps could use get with timeout.
*/
// Cast here to force the right type.
return type.cast(f.get());
} catch (Exception ex) {
// Hide exceptions without discarding them.
throw new RuntimeException(ex);
}
}
enum E implements Creator {
A {
public String create() {
return "Face";
}
},
B {
public Integer create() {
return 0xFace;
}
},
C {
public Void create() {
return null;
}
};
}
public static void main(String args[]) {
try {
Multiton<E> m = new Multiton<E>();
String face1 = m.get(E.A, String.class);
Integer face2 = m.get(E.B, Integer.class);
System.out.println("Face1: " + face1 + " Face2: " + Integer.toHexString(face2));
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
In Java 8 it is even easier:
public class Multiton<K extends Enum<K> & Multiton.Creator> {
private final ConcurrentMap<K, Object> multitons = new ConcurrentHashMap<>();
// The enums must create
public interface Creator {
public abstract Object create();
}
// The getter.
public <V> V get(final K key, Class<V> type) {
return type.cast(multitons.computeIfAbsent(key, k -> k.create()));
}
}
One thought about this pattern: the lazy instantiation isn't thread safe. This may or may not be okay, it depends on how you want to use it, but it's worth knowing. (Considering that enum initialisation in itself is thread-safe.)
Other than that, I can't see a simpler solution that guarantees full instance control, is intuitive and uses lazy instantiation.
I don't think it's an abuse of enum methods either, it doesn't differ by much from what Josh Bloch's Effective Java recommends for coding different strategies into enums.

General Java class design for property with Collection which needs to listen for change

All,
Hopefully a simple question. I am thinking of the best way to implement a class which holds a number of collections and HashMaps where the class needs to know about when they have been modified outside of the class - i.e. added/removed/changed items. Each collection/hashmap needs to be exposed as a public getter in my class at the moment.
So my basic class looks like as follows...
public class MyClass {
protected final HashMap<String, String> _values = new HashMap<String, String>();
protected final ArrayList<MyOtherClass> _other = new ArrayList<MyOtherClass>();
protected final ArrayList<MyOtherClass2> _other2 = new ArrayList<MyOtherClass2>();
// ... implementation
public HashMap<String, String> getValues() {
return _values;
}
public ArrayList<MyOtherClass> getMyOtherClassList() {
return _other;
}
public ArrayList<MyOtherClass2> getMyOtherClassList2() {
return _other2;
}
public String getContent() {
// build the content based on other/other2...
StringBuilder sb = new StringBuilder();
// iterate through both collections to build content...
// ...
return sb.toString();
}
}
public getMyOtherClass {
public String name; // has getter and setter
public String value; // has getter and setter
}
public getMyOtherClass2 {
public String name; // has getter and setter
public String value; // has getter and setter
public String somethingElse; // has getter and setter
}
I want to add a key/value to the _values based on the length of the content i.e.-
_values.add("Length", getContent().length);
So the Length value is dynamic based on what gets added to the _other and _other2.
The problem with this is exposing the _values and _other with public getters is that anything outside the class can modify them. The class will not know if items have been modified.
A couple of solutions I can think of is to make the collection/hashmap readonly - but this throws a runtime exception - if this was the case I'd like the compiler to indicate that they are read-only and throw an exception but I don't know if this is possible.
The other way would be to add a add/remove for each of the collections/maps and update the Length property accordingly - but again, if the values change in the MyOtherClass, MyClass will still not know about it.
Alternatively write my own Hashmap/List/Collection to determine when items are added/removed, and possibly have a property change listener on the getMyOtherClass, getMyOtherClass2.
Any nice solutions to this?
Thanks,
Andez
Overide the map/list implementations and insert a call-back into the add/update/remove methods that triggers an update function on the parent.
Also it's bad form to create references directly to the implementations - this is better (read up on polymorphism for reasoning):
private Map<String,String> myMap = new HashMap<String,String>();
private List<String> myList = new List<String>();
In this case you can make use of some fundamentals of the Observer design pattern to have an Object "watching" the Maps and registering each change is made to them.
Create an object contains a Map and another object that contains a List, so since you have 1 map and 2 lists you'll have 3 of those "Observable" objects. Let's name the classes "ObservableMap" and "ObservableList". You can even create an abstract class "ObservableObject" and extend it with the previously mentioned classes.
These objects won't override the Map/List implementation, they'll only act as a wrapper by wrapping the methods you'll want to track to register the state and derive the call to modify the collection. For example, I'll post some code of the ObservableMap class (I'm instantiating the map with <String,String> but you can use generics here too if it suits you).
public Class ObservableMap extends ObservableObject{
private Map<String,String> map = new LinkedHashMap<String,String>();
private Watcher observer = new Watcher();
//Example of one of the wrapper methods (the other ones are like this one)
public void putObject(String key, String value) {
watcher.notifyPut(); //You can name the method the way you like and even pass
//the new key/value pair to identify what has been added.
map.put(key,value);
}
}
Here, the Watcher class is the one that registers the canges. It can either be a completely new Object (like in this case) or you can make an Interface and implement it in an existing class of yours to be able to set it as a watcher on your Observable objects.
Not 100% sure what you are asking. If you are trying to track changes to attributes to two classes you may wish, as other people have mentioned implement the observer pattern and raise notifications in the set methods. An alternative, that I have used successfully for implementing an undo mechanism is to use aspectJ or some other AOP (Aspect Orientated Programming) tool to intercept the set methods and perform the required notifications/updates that way.
Alternatively define an interface that only provides access to the getXXX operations and return those from your model, that way nothing can change the data.

Categories

Resources