I currently am part of a project where there is an interface like this:
public interface RepositoryOperation {
public OperationResult execute(Map<RepOpParam, Object> params);
}
This interface has about ~100 implementers.
To call an implementer one needs to do the following:
final Map<RepOpParam, Object> opParams = new HashMap<RepOpParam, Object>();
opParams.put(ParamName.NAME1, val1);
opParams.put(ParamName.NAME2, val2);
Now I think that there is obviously something wrong with anything with a<Something, Object> generic declaration.
Currently this causes a caller of a OperationImpl to have to actually read the code of the operation in order to know how to build the argument map. (and this is not even the worst of the problems, but I don't want to cite them all since they are fairly obvious)
After some discussion I managed to convince my colleagues to let me do some refactoring.
It seems to me that the simplest 'fix' would be to change the interface like so:
public interface RepositoryOperation {
public OperationResult execute(OperationParam param);
}
After all the concrete operations will define (extend) their own OperationParam and the needed arguments would be visible to everybody. (which is the 'normal way' to do things like that IMHO)
So as I see it since the interface implementers are quite numerous I have several choices:
Try to change the interface and rewrite all the Operation calls to use objects instead of maps. This seems the cleanest, but I think that since the operations are a lot it might be too much work in practice. (~2 weeks with tests probably)
Add an additional method to the interface like so:
public interface RepositoryOperation {
public OperationResult execute(Map<String, Object> params);
public OperationResult execute(OperationParam params);
}
and fix the map calls whenever I come across them during functionality implementation.
Live with it (please no !).
So my question is.
Does anyone see a better approach for 'fixing' the maps and if you do would you fix them with method 1 or 2 or not fix them at all.
EDIT:
Thanks for the great answers. I would accept both Max's and Riduidel's answers if I could, but since I can't I'm leaning a bit more towards Riduidel's.
I can see a third way.
You have a map made of <RepOpParam, Object>. If I understand you correctly, what bothers you is the fact that there is no type checking. And obviously, it's not ideal. But, it is possible to move the type-checking issue from the whole parameter (your OperationParam) to individual RepOpParam. Let me explain it.
Suppose your RepOpParam interface (which currently seems like a tagging interface) is modified as it :
public interface RepOpParam<Value> {
public Value getValue(Map<RepOpParam, Object> parameters);
}
You can then update modern code by replacing old calls to
String myName = (String) params.get(ParamName.NAME1);
with new calls to
String myName = ParamName.NAME1.getValue(params);
The obvious collateral advantage being that you can now have a default value for your parameter, hidden in its very definition.
I have however to make clear that this third way is nothing more than a way to merge your two operations of the second way into only one, respecting old code prototype, while adding new powers in it. As a consequence, I would personnally go the first way, and rewrite all that "stuff", using modern objects (besides, consider taking a look at configuration librarires, which may lead you to interesting anwsers to this problem).
First of all, I think the interface is not perfect. You could add some generics to make it prettier:
public interface RepositoryOperation<P extends OperationParam, R extends OperationResult> {
public R execute(T params);
}
Now, we will need some backward compatibility code. I'd go with this:
//We are using basic types for deprecated operations
public abstract class DeprecatedRepositoryOperation implements RepositoryOperation<OperationParam, OperationResult> {
//Each of our operations will need to implement this method
public abstract OperationResult execute(Map<String, Object> params);
//This will be the method that we can call from the outside
public OperationResult execute(OperationParam params) {
Map<String, Object> paramMap = getMapFromObj(params);
return execute(paramMap);
}
}
Here is how will old operation look like:
public class SomeOldOperation extends DeprecatedRepositoryOperation {
public OperationResult execute(Map<String, Object> params) {
//Same old code as was here before. Nothing changes
}
}
New operation will be prettier:
public class DeleteOperation implements RepositoryOperation<DeleteParam, DeleteResult> {
public DeleteResult execute(DeleteParam param) {
database.delete(param.getID());
...
}
}
But the calling code can use both functions now (an example of code):
String operationName = getOperationName(); //="Delete"
Map<String, RepositoryOperation> operationMap = getOperations(); //=List of all operations
OperationParam param = getParam(); //=DeleteParam
operationMap.execute(param);
In case the operation was old one - it will use the converter method from DeprecatedRepositoryOperation.
In case the operation is a new one - it will use the new public R execute(T params) function.
It sounds like you have an unnecessary and misguided abstraction. Anytime I see an interface with one method in it, I think Strategy pattern or Action pattern, depending on whether you make the decision at runtime or not.
One way to cleanup the code is have each RepositoryOperation implementation have a constructor which takes the specific arguments it needs for the execute method to run correctly. That way there is no messy casting of the Object values in the map.
If you want to keep the execute method signature, you might be able to use generics to putter tighter bounds on the values of the Map.
Related
I am using a Java framework that provides some kind of visitor pattern for processing elements. There is an abstract super class AbstractProcessor<T> (which I cannot change) that provides a method public abstract void process(T visitedElement).
I then have defined several concrete implementations of such processors and instantiate them by Factory Pattern to then use them via their common supertype. Now, how do I get any type of information out of there? I obviously cannot simply return something, since the abstract process-method is of type void.
My only thought so far would be something like a data-field I can add to the concrete implementation (since I cannot change the abstract super class), so to do smth like this:
public class MyProcessor extends AbstractProcessor<SomeType> {
public String data;
#Override
public void process(SomeType t) {
[do stuff...]
this.data = "some important info";
}
}
But to receive this data from - lets say a list of their common super types that do not posess the data-field - I would have to do some ugly type checking and casting like this:
List<AbstractProcessor> list = getProcessors();
list.forEach(p -> {
someType.processWith(p); //someType accepts AbstractProcessor's and then runs their process-method
if(p instanceOf MyProcessor)
System.out.println( ((MyProcessor)p).data );
}
});
Is there any other way to retrieve some type of data that gets calculated during the process method this way?
I think you have an intrinsically unsolvable problem here. I understand you're saying:
You've written several AbstractProcessor subclasses.
They all do different things and produce different results.
You want to treat them all homogeneously, as instances of AbstractProcessor.
But you can't treat them all as instances of the same class, AbstractProcessor, if they all produce different results. You have to know what type of processor you have in order to interpret the results.
You have two options. The first option is to unify the results. For example, you could have an interface called ResultHandler like this:
interface ResultHandler {
void handleSumResult(int result);
void handleConcatResult(String result);
void handleSomeOtherProcessorResult(Whatever result);
}
Pass in an instance of ResultHandler (either during construction or in a separate handleResult method), then (within each processor) invoke the ResultHandler method appropriate to that processor type. If you have several different processors that generate sums in some way, at least they can all call the same handleSumResult API and you don't have to do instanceof anywhere.
The other strategy is to just abandon your attempt to treat all processors homogeneously. I think this might be the better option. Your code obviously knows what processor it needs to use, so just go ahead and instantiate that one, use it, and collect the results from whatever API you define. If there's some reason why you have to treat the processors homogeneously (e.g., the processor class is specified by the user, maybe in a configuration file), then move that abstraction up one level and instead have the user specify a class that owns the entire process of processing the data and collecting the results. Instead of specifying MyProcessor, the use specifies MySomethingElse, and then MySomethingElse both instantiates MyProcessor and handles the results.
I wouldn't use a field here. Instead: define a suitable interface, like ResultProcessor that has a T getResult() method. And then have all those subclasses that need to produce a result implement that interface.
Sure, you still have to cast, but at least you can use a generic T to be flexible and your clients can call a method instead of doing direct field access.
You can make processors "push" data to a hash map for example, which is passed in or accessible globally.
public class MyProcessor extends AbstractProcessor<SomeType> {
public Map<Object, String> data;
#Override
public void process(SomeType t) {
[do stuff...]
this.data.put(this, "some important info");
}
}
That way the client can have the information which abstract processor added which information, all it needs is access to the map.
Given the following class:
class Example implements Interface1, Interface2 {
...
}
When I instantiate the class using Interface1:
Interface1 example = new Example();
...then I can call only the Interface1 methods, and not the Interface2 methods, unless I cast:
((Interface2) example).someInterface2Method();
Of course, to make this runtime safe, I should also wrap this with an instanceof check:
if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}
I'm aware that I could have a wrapper interface that extends both interfaces, but then I could end up with multiple interfaces to cater for all the possible permutations of interfaces that can be implemented by the same class. The Interfaces in question do not naturally extend one another so inheritance also seems wrong.
Does the instanceof/cast approach break LSP as I am interrogating the runtime instance to determine its implementations?
Whichever implementation I use seems to have some side-effect either in bad design or usage.
I'm aware that I could have a wrapper interface that extends both
interfaces, but then I could end up with multiple interfaces to cater
for all the possible permutations of interfaces that can be
implemented by the same class
I suspect that if you're finding that lots of your classes implement different combinations of interfaces then either: your concrete classes are doing too much; or (less likely) your interfaces are too small and too specialised, to the point of being useless individually.
If you have good reason for some code to require something that is both a Interface1 and a Interface2 then absolutely go ahead and make a combined version that extends both. If you struggle to think of an appropriate name for this (no, not FooAndBar) then that's an indicator that your design is wrong.
Absolutely do not rely on casting anything. It should only be used as a last resort and usually only for very specific problems (e.g. serialization).
My favourite and most-used design pattern is the decorator pattern. As such most of my classes will only ever implement one interface (except for more generic interfaces such as Comparable). I would say that if your classes are frequently/always implementing more than one interface then that's a code smell.
If you're instantiating the object and using it within the same scope then you should just be writing
Example example = new Example();
Just so it's clear (I'm not sure if this is what you were suggesting), under no circumstances should you ever be writing anything like this:
Interface1 example = new Example();
if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}
Your class can implement multiple interfaces fine, and it is not breaking any OOP principles. On the contrary, it is following the interface segregation principle.
It is confusing why would you have a situation where something of type Interface1 is expected to provide someInterface2Method(). That is where your design is wrong.
Think about it in a slightly different way: Imagine you have another method, void method1(Interface1 interface1). It can't expect interface1 to also be an instance of Interface2. If it was the case, the type of the argument should have been different. The example you have shown is precisely this, having a variable of type Interface1 but expecting it to also be of type Interface2.
If you want to be able to call both methods, you should have the type of your variable example set to Example. That way you avoid the instanceof and type casting altogether.
If your two interfaces Interface1 and Interface2 are not that loosely coupled, and you will often need to call methods from both, maybe separating the interfaces wasn't such a good idea, or maybe you want to have another interface which extends both.
In general (although not always), instanceof checks and type casts often indicate some OO design flaw. Sometimes the design would fit for the rest of the program, but you would have a small case where it is simpler to type cast rather than refactor everything. But if possible you should always strive to avoid it at first, as part of your design.
You have two different options (I bet there are a lot more).
The first is to create your own interface which extends the other two:
interface Interface3 extends Interface1, Interface2 {}
And then use that throughout your code:
public void doSomething(Interface3 interface3){
...
}
The other way (and in my opinion the better one) is to use generics per method:
public <T extends Interface1 & Interface2> void doSomething(T t){
...
}
The latter option is in fact less restricted than the former, because the generic type T gets dynamically inferred and thus leads to less coupling (a class doesn't have to implement a specific grouping interface, like the first example).
The core issue
Slightly tweaking your example so I can address the core issue:
public void DoTheThing(Interface1 example)
{
if (example instanceof Interface2)
{
((Interface2) example).someInterface2Method();
}
}
So you defined the method DoTheThing(Interface1 example). This is basically saying "to do the thing, I need an Interface1 object".
But then, in your method body, it appears that you actually need an Interface2 object. Then why didn't you ask for one in your method parameters? Quite obviously, you should've been asking for an Interface2
What you're doing here is assuming that whatever Interface1 object you get will also be an Interface2 object. This is not something you can rely on. You might have some classes which implement both interfaces, but you might as well have some classes which only implement one and not the other.
There is no inherent requirement whereby Interface1 and Interface2 need to both be implemented on the same object. You can't know (nor rely on the assumption) that this is the case.
Unless you define the inherent requirement and apply it.
interface InterfaceBoth extends Interface1, Interface2 {}
public void DoTheThing(InterfaceBoth example)
{
example.someInterface2Method();
}
In this case, you've required InterfaceBoth object to both implement Interface1 and Interface2. So whenever you ask for an InterfaceBoth object, you can be sure to get an object which implements both Interface1 and Interface2, and thus you can use methods from either interface without even needing to cast or check the type.
You (and the compiler) know that this method will always be available, and there's no chance of this not working.
Note: You could've used Example instead of creating the InterfaceBoth interface, but then you would only be able to use objects of type Example and not any other class which would implement both interfaces. I assume you're interested in handling any class which implements both interfaces, not just Example.
Deconstructing the issue further.
Look at this code:
ICarrot myObject = new Superman();
If you assume this code compiles, what can you tell me about the Superman class? That it clearly implements the ICarrot interface. That is all you can tell me. You have no idea whether Superman implements the IShovel interface or not.
So if I try to do this:
myObject.SomeMethodThatIsFromSupermanButNotFromICarrot();
or this:
myObject.SomeMethodThatIsFromIShovelButNotFromICarrot();
Should you be surprised if I told you this code compiles? You should, because this code doesn't compile.
You may say "but I know that it's a Superman object which has this method!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman variable.
You may say "but I know that it's a Superman object which implements the IShovel interface!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman or IShovel variable.
Knowing this, let's look back at your code.
Interface1 example = new Example();
All you've said is that you have an Interface1 variable.
if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}
It makes no sense for you to assume that this Interface1 object also happens to implement a second unrelated interface. Even if this code works on a technical level, it is a sign of bad design, the developer is expecting some inherent correlation between two interfaces without actually having created this correlation.
You may say "but I know I'm putting an Example object in, the compiler should know that too!" but you'd be missing the point that if this were a method parameter, you would have no way of knowing what the callers of your method are sending.
public void DoTheThing(Interface1 example)
{
if (example instanceof Interface2)
{
((Interface2) example).someInterface2Method();
}
}
When other callers call this method, the compiler is only going to stop them if the passed object does not implement Interface1. The compiler is not going to stop someone from passing an object of a class which implements Interface1 but does not implement Interface2.
Your example does not break LSP, but it seems to break SRP. If you encounter such case where you need to cast an object to its 2nd interface, the method that contains such code can be considered busy.
Implementing 2 (or more) interfaces in a class is fine. In deciding which interface to use as its data type depends entirely on the context of the code that will use it.
Casting is fine, especially when changing context.
class Payment implements Expirable, Limited {
/* ... */
}
class PaymentProcessor {
// Using payment here because i'm working with payments.
public void process(Payment payment) {
boolean expired = expirationChecker.check(payment);
boolean pastLimit = limitChecker.check(payment);
if (!expired && !pastLimit) {
acceptPayment(payment);
}
}
}
class ExpirationChecker {
// This the `Expirable` world, so i'm using Expirable here
public boolean check(Expirable expirable) {
// code
}
}
class LimitChecker {
// This class is about checking limits, thats why im using `Limited` here
public boolean check(Limited limited) {
// code
}
}
Usually, many, client-specific interfaces are fine, and somewhat part of the Interface segregation principle (the "I" in SOLID). Some more specific points, on a technical level, have already been mentioned in other answers.
Particularly that you can go too far with this segregation, by having a class like
class Person implements FirstNameProvider, LastNameProvider, AgeProvider ... {
#Override String getFirstName() {...}
#Override String getLastName() {...}
#Override int getAge() {...}
...
}
Or, conversely, that you have an implementing class that is too powerful, as in
class Application implements DatabaseReader, DataProcessor, UserInteraction, Visualizer {
...
}
I think that the main point in the Interface Segregation Principle is that the interfaces should be client-specific. They should basically "summarize" the functions that are required by a certain client, for a certain task.
To put it that way: The issue is to strike the right balance between the extremes that I sketched above. When I'm trying to figure out interfaces and their relationships (mutually, and in terms of the classes that implement them), I always try to take a step back and ask myself, in an intentionally naïve way: Who is going to receive what, and what is he going to do with it?
Regarding your example: When all your clients always need the functionality of Interface1 and Interface2 at the same time, then you should consider either defining an
interface Combined extends Interface1, Interface2 { }
or not have different interfaces in the first place. On the other hand, when the functionalities are completely distinct and unrelated and never used together, then you should wonder why the single class is implementing them at the same time.
At this point, one could refer to another principle, namely Composition over inheritance. Although it is not classically related to implementing multiple interfaces, composition can also be favorable in this case. For example, you could change your class to not implement the interfaces directly, but only provide instances that implement them:
class Example {
Interface1 getInterface1() { ... }
Interface2 getInterface2() { ... }
}
It looks a bit odd in this Example (sic!), but depending on the complexity of the implementation of Interface1 and Interface2, it can really make sense to keep them separated.
Edited in response to the comment:
The intention here is not to pass the concrete class Example to methods that need both interfaces. A case where this could make sense is rather when a class combines the functionalities of both interfaces, but does not do so by directly implementing them at the same time. It's hard to make up an example that does not look too contrived, but something like this might bring the idea across:
interface DatabaseReader { String read(); }
interface DatabaseWriter { void write(String s); }
class Database {
DatabaseConnection connection = create();
DatabaseReader reader = createReader(connection);
DatabaseReader writer = createWriter(connection);
DatabaseReader getReader() { return reader; }
DatabaseReader getWriter() { return writer; }
}
The client will still rely on the interfaces. Methods like
void create(DatabaseWriter writer) { ... }
void read (DatabaseReader reader) { ... }
void update(DatabaseReader reader, DatabaseWriter writer) { ... }
could then be called with
create(database.getWriter());
read (database.getReader());
update(database.getReader(), database.getWriter());
respectively.
With the help of various posts and comments on this page, a solution has been produced, which I feel is correct for my scenario.
The following shows the iterative changes to the solution to meet SOLID principles.
Requirement
To produce the response for a web service, key + object pairs are added to a response object. There are lots of different key + object pairs that need to be added, each of which may have unique processing required to transform the data from the source to the format required in the response.
From this it is clear that whilst the different key / value pairs may have different processing requirements to transform the source data to the target response object, they all have a common goal of adding an object to the response object.
Therefore, the following interface was produced in solution iteration 1:
Solution Iteration 1
ResponseObjectProvider<T, S> {
void addObject(T targetObject, S sourceObject, String targetKey);
}
Any developer that needs to add an object to the response can now do so using an existing implementation that matches their requirement, or add a new implementation given a new scenario
This is great as we have a common interface which acts as a contract for this common practise of adding response objects
However, one scenario requires that the target object should be taken from the source object given a particular key, "identifier".
There are options here, the first is to add an implementation of the existing interface as follows:
public class GetIdentifierResponseObjectProvider<T extends Map, S extends Map> implements ResponseObjectProvider<T, S> {
public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
targetObject.put(targetKey, sourceObject.get("identifier"));
}
}
This works, however this scenario could be required for other source object keys ("startDate", "endDate" etc...) so this implementation should be made more generic to allow for reuse in this scenario.
Additionally, other implementations may require more context information to perform the addObject operation... So a new generic type should be added to cater for this
Solution Iteration 2
ResponseObjectProvider<T, S, U> {
void addObject(T targetObject, S sourceObject, String targetKey);
void setParams(U params);
U getParams();
}
This interface caters for both usage scenarios; the implementations that require additional params to perform the addObject operation and the implementations that do not
However, considering the latter of the usage scenarios, the implementations that do not require additional parameters will break the SOLID Interface Segregation Principle as these implementations will override getParams and setParams methods but not implement them. e.g:
public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S, U> {
public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
targetObject.put(targetKey, sourceObject.get(U));
}
public void setParams(U params) {
//unimplemented method
}
U getParams() {
//unimplemented method
}
}
Solution Iteration 3
To fix the Interface Segregation issue, the getParams and setParams interface methods were moved into a new Interface:
public interface ParametersProvider<T> {
void setParams(T params);
T getParams();
}
The implementations that require parameters can now implement the ParametersProvider interface:
public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S>, ParametersProvider<U>
private String params;
public void setParams(U params) {
this.params = params;
}
public U getParams() {
return this.params;
}
public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
targetObject.put(targetKey, sourceObject.get(params));
}
}
This solves the Interface Segregation issue but causes two more issues... If the calling client wants to program to an interface, i.e:
ResponseObjectProvider responseObjectProvider = new GetObjectBySourceKeyResponseObjectProvider<>();
Then the addObject method will be available to the instance, but NOT the getParams and setParams methods of the ParametersProvider interface... To call these a cast is required, and to be safe an instanceof check should also be performed:
if(responseObjectProvider instanceof ParametersProvider) {
((ParametersProvider)responseObjectProvider).setParams("identifier");
}
Not only is this undesirable it also breaks the Liskov Substitution Principle - "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"
i.e. if we replaced an implementation of ResponseObjectProvider that also implements ParametersProvider, with an implementation that does not implement ParametersProvider then this could alter the some of the desirable properties of the program... Additionally, the client needs to be aware of which implementation is in use to call the correct methods
An additional problem is the usage for calling clients. If the calling client wanted to use an instance that implements both interfaces to perform addObject multiple times, the setParams method would need to be called before addObject... This could cause avoidable bugs if care is not taken when calling.
Solution Iteration 4 - Final Solution
The interfaces produced from Solution Iteration 3 solve all of the currently known usage requirements, with some flexibility provided by generics for implementation using different types. However, this solution breaks the Liskov Substitution Principle and has a non-obvious usage of setParams for the calling client
The solution is to have two separate interfaces, ParameterisedResponseObjectProvider and ResponseObjectProvider.
This allows the client to program to an interface, and would select the appropriate interface depending on whether the objects being added to the response require additional parameters or not
The new interface was first implemented as an extension of ResponseObjectProvider:
public interface ParameterisedResponseObjectProvider<T,S,U> extends ResponseObjectProvider<T, S> {
void setParams(U params);
U getParams();
}
However, this still had the usage issue, where the calling client would first need to call setParams before calling addObject and also make the code less readable.
So the final solution has two separate interfaces defined as follows:
public interface ResponseObjectProvider<T, S> {
void addObject(T targetObject, S sourceObject, String targetKey);
}
public interface ParameterisedResponseObjectProvider<T,S,U> {
void addObject(T targetObject, S sourceObject, String targetKey, U params);
}
This solution solves the breaches of Interface Segregation and Liskov Substitution principles and also improves the usage for calling clients and improves the readability of the code.
It does mean that the client needs to be aware of the different interfaces, but since the contracts are different this seems to be a justified decision especially when considering all the issues that the solution has avoided.
The problem you describe often comes about through over-zealous application of the Interface Segregation Principle, encouraged by languages' inability to specify that members of one interface should, by default, be chained to static methods which could implement sensible behaviors.
Consider, for example, a basic sequence/enumeration interface and the following behaviors:
Produce an enumerator which can read out the objects if no other iterator has yet been created.
Produce an enumerator which can read out the objects even if another iterator has already been created and used.
Report how many items are in the sequence
Report the value of the Nth item in the sequence
Copy a range of items from the object into an array of that type.
Yield a reference to an immutable object that can accommodate the above operations efficiently with contents that are guaranteed never to change.
I would suggest that such abilities should be part of the basic sequence/enumeration interface, along with a method/property to indicate which of the above operations are meaningfully supported. Some kinds of single-shot on-demand enumerators (e.g. an infinite truly-random sequence generator) might not be able to support any of those functions, but segregating such functions into separate interfaces will make it much harder to produce efficient wrappers for many kinds of operations.
One could produce a wrapper class that would accommodate all of the above operations, though not necessarily efficiently, on any finite sequence which supports the first ability. If, however, the class is being used to wrap an object that already supports some of those abilities (e.g. access the Nth item), having the wrapper use the underlying behaviors could be much more efficient than having it do everything via the second function above (e.g. creating a new enumerator, and using that to iteratively read and ignore items from the sequence until the desired one is reached).
Having all objects that produce any kind of sequence support an interface that includes all of the above, along with an indication of what abilities are supported, would be cleaner than trying to have different interfaces for different subsets of abilities, and requiring that wrapper classes make explicit provision for any combinations they want to expose to their clients.
I'm writing a class which will make time consuming calculations on parametres stored in a list of MyObjects. Since I wanted to have easy access to a number of List's features, I decided to write it extending a list type (an alternative would be to have a List as one of the fields in my class and rewrite all methods I'm going to use, but it looks like an overcomplication). Since the calculations are pretty complex and time consuming, while the result depends solely on the stored parameters (no time influence, no hidden dependencies, etc), I decided to cache the result. So my code looks more or less like this:
public class Calculator extends ArrayList<MyObject> {
private double Result = Double.NaN;
public double getResult() {
if (Double.isNaN(Result)) {
Result = CalculateResult();
}
return Result;
}
}
This way, when the method getResult() is called for the first time it calculates the result, stores it, and then reuses during subsequent calls.
Now, the list's contents can be modified with various methods, and many modifications should clear the cache. To achieve this, normally I would write something like:
public void add(MyObject newvalue) {
super.add(newvalue);
Result = Double.NaN;
}
However, it does not work, because "super" refers to the generic ArrayList class, so the compiler produces a type error.
An obvious trick on my level would be to create an interim class, which would implement ArrayList of MyObject and make Calculator extend this interim class:
public class MyArrayList extends ArrayList<MyObject> {
}
public class Calculator extends MyArrayList {
}
But it looks like an overcomplication again. Isn't there a more elegant method to achieve this result? Or perhaps, is there a mechanism similar to trigger in SQL, which would force my class clear the cache whenever any modification is made to the List?
The method add should return boolean value, so all what you need to do is
public boolean add(MyObject newvalue) {
boolean retVal = super.add(newvalue);
Result = Double.NaN;
return retVal ;
}
This is a good example as to when composition over inheritance really makes sense for code design. Your class will become cluttered with unnecessary operations, when it only really needs to have an instance of a List of some kind floating around. It also means that you're not hard-dependent on the ArrayList implementation; for instance, what if your algorithms called for a LinkedList instead?
But, if you really want to fix what you have...
First and foremost, the reason you're getting the compiler error is because, as far as Java is concerned, you're trying to override the add method, but don't quite have the signature right.
The correct signature is specified as boolean add(E), but you're overriding it with a signature of void add(E). The types don't match, so you won't get a successful override, and Java will not compile the class, as you can see.
Next, creating more classes to accomplish the same thing as inheriting and properly overriding the ArrayList class will not gain you anything; if anything, it will be more of an overcomplication.
If i have heterogeneous collection for which I know exactly the types i'm going to place is there a way to enforce this.
For example take this scenario say i have a map that has a String key and value which can be on of three unrelated types. Now I know that I will only put ClassA and ClassB or java.lang.String
for example here is the code
public HetroCollection
{
public Map<String,Object> values;
}
public ClassA
{
}
public ClassB
{
}
public static void Main(String args[])
{
HetroCollection collection = new HetroCollection();
collection.values.add("first", new ClassA());
collections.values.add("second", new ClassB());
collections.values.add("third" , "someString");
//BAD want to stop random adds
collections.values.("fourth" , new SomeRandomClass());
}
The Options I have thought of are:
have the classes implement a common interface and use Generics on the Map (Problem with this is if this also involves library classes either JDK or third party then changing class is not an option
hide the Map and provide put Methods which are paratemized like
put(String key , ClassA value);
put(String key , ClassB value);
put(String key, String value);
get(String key);
Rethink design and not use heterogeneous collection (not sure how I would represent this any other way)
Looking for the best practice answer for this.
I think that the "best practice" solutions are either your first and third options, provided that circumstances allow it.
Another option that you haven't considered is something like this:
public class MyMap extends HashMap<String, Object> {
...
// constructors
...
#Override
public void put(String key, Object value) {
if (value instanceof ClassA || value instanceof ClassB) {
super.put(key, value);
} else {
throw new IllegalArgumentException("Verbotten!");
}
}
...
}
You could combine this with your second option so that there is a statically typed option, and possibly even label the put(String, Object) method as deprecated to discourage its use.
And finally, there is the option of just ignoring the problem, and relying on the application programmer to not put random stuff into the map. Depending on the circumstances, this might even be the best solution.
Well, you've already proven your first thought to not be an option. The second thought would be the best option, if you really need this functionality. Otherwise the best option is to rethink your approach. But, it's easier to help if we knew a little context.
There is a fourth option:
If you want to stick instances of exactly these types into a collection, chances are they have something in common. If you can not introduce a common supertype to express that commonality, you can still introduce a parallel class hierarchy with such a common superclass, and declare your map to hold items of that type.
// You can find a better name ;-)
abstract class Foo {
public abstract void foo();
public void bar() {
// something generic
}
public abstract void visit(FooVisitor visitor);
}
class ClassAFoo {
final ClassA delegate;
// Constructor and implementations for foo()
}
class ClassBFoo {
final ClassB delegate;
// Constructor and implementations for foo()
}
class StringFoo {
final String delegate;
// Constructor and implementations for foo()
}
Advantages:
statically type safe
you can add methods to the common type or implement the visitor pattern to switch on the type of wrapped value
the compiler can check that you have handled all types when working with the map (in contrast to using a series of if-statements to switch on the type)
Disadvantages:
boilerplate code, complexity
There's a great facility in Java for this called classes. Given your example, you might write one like this:
public class Foo {
private ClassA first;
private ClassB second;
private String someString;
...
public void setFirst(ClassA first) {
this.first = first;
}
public ClassA getFirst() {
return first;
}
...
}
Seriously, given what you've said this sounds like exactly what you want. If you only want to allow specific keys, with values that may only be of specific types (that depend on the key itself)... that's a class. If there's some really strong reason that you need to use String map keys here (and this seems unlikely to me), please explain.
Edit:
When I answered this I was under the impression for some reason that you needed to enforce only specific keys mapping to specific types of values. Looking at it again, it seems like that may not be the case. If that isn't the case, I think your best option is rethinking the design (giving an example of why you need to do this might be helpful). If you do that and don't come up with anything, I think #2 is the best option. It enforces your restrictions on the types of values the map can have in a somewhat typesafe way.
In theory type safety with mixed objects from a List can be achieved using HList in Functional Java. See blog post and Examples. Also relevant this article from IBM developerworks. I wrote in theory because in practice the type declaration can only cope with a limited number of elements and it grows rapidly.
A little background first. I am looking into the possibility of implementing Ruby's ActiveRecord in Java as cleanly and succinctly as possible. To do this I would need to allow for the following type of method call:
Person person = Person.find("name", "Mike");
Which would resolve to something like:
ActiveRecord.find(Person.class, "name", "Mike");
The plan is to have Person extend ActiveRecord, which would have a static find method with two parameters (column, value). This method would need to know it was called via Person.find and not another domain class like Car.find and call the find(Class, String, Object) method to perform the actual operation.
The problem I am running into is the finding out via which child class of ActiveRecord the static find method (two param) was called. The following is a simple test case:
public class A {
public static void testMethod() {
// need to know whether A.testMethod(), B.testMethod(), or C.testMethod() was called
}
}
public class B extends A { }
public class C extends A { }
public class Runner {
public static void main(String[] args) {
A.testMethod();
B.testMethod();
C.testMethod();
}
}
Solutions found so far are load-time or compile time weaving using aspectJ. This would involve placing a call interceptor on the testMethod() in A and finding out what signature was used to call it. I am all for load time weaving but the set up of setting this up (via VM args) is a bit complex.
Is there a simpler solution?
Is this at all possible in java or would need to be done in something like groovy/ruby/python?
Would the approach of using something like ActiveRecord.find for static loads and Person.save for instances be better overall?
You cannot override static methods in Java, so any calls to the static method via a subclass will be bound to the base class at compile time. Thus a call to B.testMethod() will be bound to A.testMethod before the application is ever run.
Since you are looking for the information at runtime, it will not be available through normal Java operations.
As others have noted, I don't think the problem is solvable in Java as you pose it. A static method is not really inherited in the same way that a non-static method is. (Excuse me if I'm not using the terminology quite right.)
Nevertheless, it seems to me there are many ways you could accomplish the desired result if you're willing to modify your interface a little.
The most obvious would be to just make the call using the parent class. What's wrong with writing
Person person=(Person)ActiveRecord.find(Person.class, "name", "Mike");
?
Alternatively, you could create an instance of the record type first and then do a find to fill it in. Like
Person person=new Person();
person.find("name", "Mike");
At that point you have a Person object and if you need to know it's class from within a function in the supertype, you just do "this.getClass()".
Alternatively, you could create a dummy Person object to make the calls against, just to let you do the getClass() when necessary. Then your find would look something like:
Person dummyPerson=new Person();
Person realPerson=dummyPerson.find("name", "Mike");
By the way, seems to me that any attempt to have a generic ActiveRecord class is going to mean that the return type of find must be ActiveRecord and not the particular record type, so you'll probably have to cast it to the correct type upon return from the call. The only way to beat that is to have an explicit override of the find in each record object.
I've had plenty of times that I've written some generic record-processing code, but I always avoid creating Java objects for each record type, because that invariably turns into writing a whole bunch of code. I prefer to just keep the Record object completely generic and have field names, indexes, whatever all be internal data and names. If I want to retrieve the "foo" field from the "bar" record, my interface will look something like this:
Record bar=Record.get(key);
String foo=bar.get("foo");
Rather than:
BarRecord bar=BarRecord.get(key);
String foo=bar.getFoo();
Not as pretty and it limits compile-time error-checking, but it's way less code to implement.
You would not do this in Java. You would probably do something more like:
public interface Finder<T, RT, CT>
{
T find(RT colName, CT value);
}
public class PersonFinder
implements Finder<Person, String, String>
{
public Person find(String nameCol, String name)
{
// code to find a person
}
}
public class CarFinder
implements Finder<Car, String, int>
{
public Person find(String yearCol, int year)
{
// code to find a car
}
}
It is possible but it is expensive.
If you can find a way to only call it once then you're set.
You can create a new exception and look at the first frame and then you'll know who call it. Again the problem is it is not performant.
For instance with this answer it is possible to create a logger like this:
class MyClass {
private static final SomeLogger logger = SomeLogger.getLogger();
....
}
And have that logger create a different instance depending on who called it.
So, in the same fashion, you could have something like:
class A {
public static void myStatic() {
// find out who call it
String calledFrom = new RuntimeException()
.getStackTrace()[1].getClassName();
}
}
This is fine for a one time initialization. But not for 1,000 calls. Although I don't know if a good VM may inline this for you.
I would go for AspectJ path.
My theory on this, having built something similar, is to use a code generation strategy to create a delegate for each class which contains the method. You can't have quite as much hidden code in Java, it's probably not worth the effort as long as you generate something reasonable. If you really want to hide it, you could do something like...
public class Person extends PersonActiveRecord
{
}
//generated class, do not touch
public class PersonActiveRecord extends ActiveRecord
{
public Person find(Map params)
{
ActiveRecord.find(Person.class, params);
}
}
But it tends to mess up your inheritance hierarchy too much. I say just generate the classes and be done with it. Not worth it to hide the find method.
You can do it very manually by creating a hackish constructor.
A example = new B(B.class);
And have the superclass constructor store the class that's passed to it.
I don't think the thrown exception above would work, but if you'd want to ever do something like that without creating an exception...
Thread.currentThread().getStackTrace()
You may be able to do it much more smoothly with meta-programming and javassist.
I suppose you want to implement ActiveRecord in Java. When I decided to do the same, I hit the same problem. This is a hard one for Java, but I was able to overcome it.
I recently released entire framework called ActiveJDBC here:
http://code.google.com/p/activejdbc/
If interested, you can look at sources to see how this was implemented. Look at the Model.getClassName() method.
This is how I solved getting a class name from a static method. The second problem was to actually move all the static methods from a super class to subclasses (this is a cludgy form of inheritance after all!). I used Javassist for this. The two solutions allowed me to implement ActiveRecord in Java completely.
The byte code manipulation originally was done dynamically when classes loaded, but I ran into some class loading problems in Glassfish and Weblogic, and decided to implement static bytecode manipulation. This is done by a http: activejdbc.googlecode.com/svn/trunk/activejdbc-instrumentation/ Maven plugin.
I hope this provides an exhaustive answer to your question.
Enjoy,
Igor