I have an abstract class X and some classes who extend this class, call them A, B and C.
In some other class Y I have a few methodcalls that depend on the type of the class. The if-else statement looks like this:
public class Y implements InterfaceY {
public Y(){
}
public String doStuff (X x, Boolean flag) {
String s = "";
if (x instanceof A) {
doStuff((A) x));
} else if (x instanceof B) {
doStuff((B) x));
} else if (x instanceof C) {
doStuff((C) x, flag);
} else {
throw new Exeption();
}
return s;
private String doStuff(A a) {
return "";
}
private String doStuff(B b) {
return "";
}
private String doStuff(C c, Boolean flag) {
return "";
}
}
Note that all methods have the same name (doStuff()) but depending on the class (and sometimes flag) call a different method implementation of that method. Of course this looks horrible and gets immensely complicated once the classed that are extended from X increase.
Is there any way that I can somehow create an intermediate Interface that (or something else) that takes care of the majority (or all) of the if-else statements?
First take these methods out of here, and put them in the A, B and C class respectively, implementing the X interface.
private String doStuff(A a) {
return "";
}
private String doStuff(B b) {
return "";
}
private String doStuff(C c, Boolean flag) {
return "";
}
Then:
if (x instanceof A) {
doStuff((A) x));
} else if (x instanceof B) {
doStuff((B) x));
} else if (x instanceof C) {
doStuff((C) x, flag);
can just be x.doStuff(); (you don't even have to pass the A, B, C because that will be this inside the method. The flag you'll have to mess around with depending more specifically on your code. for example, the other 2 doStuff methods could accept the flag as well, but just ignore it)
What about implementing a Handler interface then map it by supported type:
public interface Handler<T extends X>{
Class<T> supportedClass;
void doStuff(T value, Object...args);
}
public class Y implements InterfaceY {
private Map<Class<?>, Handler<?>> handlers;
public Y(List<Handler<?>> handlers){
// populate map
}
public void process(X value){
handler.get(value.getClass).doStuff(X, ...);
// you would have to figure out how to determine when other values are needed
}
}
What about some double dispatch?
class X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
public static void main(String [] args) {
//X x = new A();
X x = new B();
Y y = new Y();
y.doStuff(x, false);
}
public X getThis() {
return this;
}
}
class A extends X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
}
class B extends X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
}
class C extends X {
public String letYdoStuff(Y y, Boolean flag) {
return y.doStuff(this, flag);
}
}
class Y {
public Y(){
}
public String doStuff (X x, Boolean flag) {
String s = "";
return x.letYdoStuff(this, flag);
}
public String doStuff(A a, Boolean flag) {
System.out.println("in A");
return "";
}
public String doStuff(B b, Boolean flag) {
System.out.println("in B");
return "";
}
public String doStuff(C c, Boolean flag) {
System.out.println("in C");
return "";
}
}
APPROACH 1
Use the state pattern. It takes care of your problem and eliminates the ifs and elses.
Here is the java example.
The state pattern delegates the methods calls to objects that implement the same interface but with different behaviour.
State pattern example:
public class StatePatternExample {
public static void main(String[] args) {
Girlfriend anna = new Girlfriend();
// OUTPUT
anna.kiss(); // *happy*
anna.greet(); // Hey, honey!
anna.provoke(); // :#
anna.greet(); // Leave me alone!
anna.kiss(); // ...
anna.greet(); // Hey, honey!
}
}
interface GirlfriendInteraction extends GirlfriendMood {
public void changeMood(GirlfriendMood mood);
}
class Girlfriend implements GirlfriendInteraction {
private GirlfriendMood mood = new Normal(this);
public void provoke() {
mood.provoke();
}
public void kiss() {
mood.kiss();
}
public void greet() {
mood.greet();
}
public void changeMood(GirlfriendMood mood) {
this.mood = mood;
}
}
interface GirlfriendMood {
public void provoke();
public void kiss();
public void greet();
}
class Angry implements GirlfriendMood {
private final GirlfriendInteraction context;
Angry(GirlfriendInteraction context) { // more parameters, flags, etc. possible
this.context = context;
}
public void provoke() {
System.out.println("I hate you!");
}
public void kiss() {
System.out.println("...");
context.changeMood(new Normal(context));
}
public void greet() {
System.out.println("Leave me alone!");
}
}
class Normal implements GirlfriendMood {
private final GirlfriendInteraction context;
Normal(GirlfriendInteraction context) {
this.context = context;
}
public void provoke() {
System.out.println(":#");
context.changeMood(new Angry(context));
}
public void kiss() {
System.out.println("*happy*");
}
public void greet() {
System.out.println("Hey, honey!");
}
}
As you can see, the class Girlfriend has no ifs and elses. It looks pretty clean.
The class Girlfriend corresponds to your abstract class X, the classes Normal and Angry correspond to A, B and C.
Your class Y then directly delegates to X without checking any cases.
APPROACH 2
Use the command pattern. You could then hand over a command object to Ys doStuff() method and just execute it.
This can be a difficult problem. I think Cruncher's solution, add
doStuff to X and override it in A, B, C, is the simplest and
best solution when it's appropriate. However, it isn't always
appropriate, because of the Single responsibility
principle.
(I think that's the correct term. My apologies if I get some
terminology wrong, I'm not entirely up-to-date on all of the terms.)
The idea is that you shouldn't necessarily doStuff to X if it has
nothing to do with the purpose of X. If X and Y are part of the
same "team", i.e. they've been both set up to serve the purpose of one
particular application, then it's probably OK.
But suppose you have an abstract Shape class that has subclasses
Circle, Square, Undecagon, RandomBlob, etc. There will be
some methods that belong in the Shape class that would be useful to
any application that uses the Shape class. But now say you are
writing a game that uses some of those shapes, and you want a
polymorphic operation that determines what happens when the shape gets
eaten by a flying monkey. You wouldn't want to add an abstract
computeEatenByFlyingMonkey method to your Shape class, even if the
class were your own creation and not in someone else's library,
because that would be just too specific for a class that could be
generally used for other purposes than this one game.
I can think of a couple ways to approach this.
If it's not appropriate (or not possible) to add doStuff to X, but
if A, B, and C are more closely connected to your application so
that adding doStuff to them is appropriate, you can add another
class:
public abstract class XWithStuff extends X {
// repeat any constructors in X, making them all be just
// calls to super(...)
public abstract void doStuff (Boolean flag);
}
public class A extends XWithStuff {
#Override
public void doStuff (Boolean flag) { ... }
}
and so on for every other class. (XWithStuff is just an example
name; in real life, a name that contains both "X" and some reference
to the application or purpose is probably better.) (P.S. I don't know
why you're using Boolean instead of boolean but I'm leaving it
that way in case there's a good reason.)
If it's also not appropriate or not possible to add doStuff to A,
B, and C, here's a possible solution:
public interface StuffInterface {
public void doStuff (Boolean flag);
}
public class AWithStuff extends A implements StuffInterface {
#Override
public void doStuff (Boolean flag) { ... }
}
and then in your program create objects of class AWithStuff instead
of A, etc. To call doStuff on an X:
void doStuff (X x, Boolean flag) {
if (x instanceof StuffInterface) {
((StuffInterface) x).doStuff (flag);
} else {
throw new IllegalArgumentException ();
}
}
If that's not an option and you have to deal directly with A, B,
etc., and you can't add doStuff to those classes, then any solution
will be a bit hacky. If you don't want to use if-then-else, you
could look into the visitor pattern, or you could conceivably create
a HashMap<Class<?>,Interf> that would map A.class, B.class,
etc., to some interface object that calls the correct doStuff. But
I haven't worked out the details. (Actually, the "visitor pattern" probably wouldn't be appropriate unless you have some sort of complex structure composed of objects of type X.)
Separate a DoStuffOperation, create the relative factory and use them.
public interface DoStuffOperation<T> {
String doStuff(T x);
}
public class ADoStuffImpl implements DoStuffOperation<A> {
public String doStuff(A x) {
return "doStuff<A>";
}
}
public class ADoStuffWithFlagImpl implements DoStuffOperation<A> {
public String doStuff(A x) {
return "doStuffWithFlag<A>";
}
}
public class DoStuffImplFactory {
public final static <T extends X> DoStuffOperation<X> getDoStuff(Class<T> xClass,boolean flag) {
DoStuffOperation<X> impl = null;
if(xClass.equals(A.class))
{
if(flag)
impl = (DoStuffOperation)new ADoStuffWithFlagImpl();
else
impl = (DoStuffOperation)new ADoStuffImpl();
}
}
return impl;
}
}
public class Y implements InterfaceY {
public String doStuff (X x, Boolean flag) {
return DoStuffImplFactory.getDoStuff(x.getClass(),flag).doStuff(x);
}
}
In this way you don't have to refactor call to Y.doStuff() or X and derived classes.
You can't remove at all some sort of instanceof to decide which implementation of doStuff() use unless X classes implements a DoStuffCreator interface like:
interface DoStuffCreator {
DoStuffOperation getDoStuffOperation(boolean flag);
}
X and A are your classes. You can also construct using reflection or other automatic way (external property file and so on).
Related
I have two interfaces in Java (version 8) which are very similar.
I cannot change the interfaces and cannot change the classes which implement them.
public interface A {
int get();
}
public interface B {
int get();
int somethingelse();
}
Now I have a function that its implementation fits both interfaces (almost).
I want it to do something like that:
public int foo((A | B) p) {
int ret = 0;
if (p instanceof B) {
ret = p.somthingelse();
}
return ret + p.get();
}
I don't want to use inspection because this function is on the main pipeline of my program.
I want it to have good performance.
Is it possible to do this in Java?
Edit:
A simple solution will be to copy/paste foo() and implement it differently for each interface.
But in reality foo() and the interfaces are much longer than that and I'm trying to avoid code duplication.
There's unfortunately no way to create that kind of retroactive relationship between two unrelated types.
If you can change foo() and its invocations, you could be able to make use of functional interfaces matching the signatures that you invoke inside foo. I'm using IntSupplier here, with corresponding lambda expressions using concrete implementations of A and B.
Say you have these implementations:
class AImpl implements A {
//implementation
}
class BImpl implements B {
//implementation
}
You can change foo to something like:
public int foo(IntSupplier get, IntSupplier somethingElse) {
int ret = 0;
if (somethingElse != null) {
ret = somethingElse.getAsInt();
}
return ret + get.getAsInt();
}
And call it this way:
A a = new AImpl();
B b = new BImpl();
int result = this.foo(a::get, b::somethingelse);
The only way I can imagine is this:
public int foo(A p) {
return internal_foo(p);
}
public int foo(B p) {
return internal_foo(p);
}
private int internal_foo(Object p) {
if (p instanceof A) {
return ((A)p).get();
}
if (p instanceof B) {
B b = (B)p;
ret = b.somthingelse();
return ret + b.get();
}
throw new ClassCastException("Wrong type");
}
Afaik, Java doesn't support this directly, but you could manually create a "type-union wrapper". Something like this:
abstract class AorB {
public static AorB wrap(A a) {
return new AWrapper(a);
}
public static AorB wrap(B b) {
return new BWrapper(b);
}
abstract int get();
abstract int somethingElse();
}
class AWrapper extends AorB {
private final A a;
AWrapper(A a) {
this.a = a;
}
#Override
int get() {
return a.get();
}
#Override
int somethingElse() {
return 0;
}
}
class BWrapper extends AorB {
private final B b;
BWrapper(B b) {
this.b = b;
}
#Override
int get() {
return b.get();
}
#Override
int somethingElse() {
return b.somethingElse();
}
}
// and then
public int foo(A a) {
return fooImpl(AorB.wrap(a));
}
public int foo(B b) {
return fooImpl(AorB.wrap(b));
}
int fooImpl(AorB p) {
return p.get() + p.somethingElse();
}
You could also add some inspection functions like hasSomethingElse(), if there's no appropriate default value to return, like the 0 above..
I want to write a method which would receive different type of objects dynamically. Once I receive the dynamic object, I have logic inside method to do something based on the properties associated with that object. It would be something like below:
MainClass{
class1 obj1;//all these are pojo
class2 obj2;
class3 obj3;
method1(<dynamic_object>)
}
method1(<dynamic_object>){
if(dynamic_object.property 1 == true){
callmethod2(dynamic_object.property 1)
}
else{
callmethod3(dynamic_object.property 1)
}
}
Here dynamic_objects are of different type.
How can I achieve this in Java? I do not want to use reflection here.
In order to recognize the type of the object you can use the instanceof operator.
private void instanceOfMethodExample(Object object){
if(object instanceof String)
print("Its a String!");
else if(object instanceof Integer)
print("Its an Int!");
else
print("Its a " + object.getClass().getName()); // by calling getClass().getName() method you take the class name of the object as a String
}
Use the visitor pattern, In a nutshell you can have something like this:
public class Visitor {
interface UserVisitor {
public void visit(CarUser user1);
public void visit(BusUser user2);
}
static class VehicleVisitor implements UserVisitor {
private Car vehicle;
private Bus bus;
VehicleVisitor(Car vehicle, Bus bus) {
this.vehicle = vehicle;
this.bus = bus;
}
public void visit(CarUser user1) {
user1.setCar(vehicle);
}
public void visit(BusUser user2) {
user2.setBus(bus);
}
}
interface UserVisitorClient {
void accept(UserVisitor visitor);
}
static class CarUser implements UserVisitorClient {
private Car car;
public void accept(UserVisitor visitor) {
visitor.visit(this);
}
public void setCar(Car car) {
this.car = car;
}
public Car getCar() {
return car;
}
}
static class BusUser implements UserVisitorClient {
private Bus bus;
public void accept(UserVisitor visitor) {
visitor.visit(this);
}
public void setBus(Bus bus) {
this.bus = bus;
}
public Bus getBus() {
return bus;
}
}
static class Car {
#Override
public String toString() {
return "CAR";
}
}
static class Bus {
#Override
public String toString() {
return "BUS";
}
}
public static void main(String[] args) {
List<UserVisitorClient> users = new ArrayList<UserVisitorClient>();
CarUser user1 = new CarUser();
users.add(user1);
BusUser user2 = new BusUser();
users.add(user2);
for (UserVisitorClient user : users) {
VehicleVisitor visitor = new VehicleVisitor(new Car(), new Bus());
user.accept(visitor);
}
System.out.println(user1.getCar());
System.out.println(user2.getBus());
}
}
Which is just an example. But it shows that basically you can use this pattern to support what you're trying to accomplish.
In your code, you could have:
void method1(VisitorClient client) {
client.accept(someVisitor);
}
This will allow you to reach o more object oriented solution, relying in polymorphism instead of reflection or instanceof.
The best option is to use a common interface
interface HasProperty {
boolean isSet();
}
void method1(HasProperty object) {
if (object.isSet())
method2(object);
else
method3(object);
}
Or even better have a method to call to perform an action.
interface MethodOne {
void method1();
}
MethodOne object = ...
object.method1(); // calls the appropriate method for this object.
Use superclass of all objects- "Object" and check the type of object using instanceof operator.
method1(Object obj){
if(obj instanceof dynamic_object){
callmethod2(dynamic_object.property 1)
}
else if(obj instanceof dynamic_object2) {
callmethod3(dynamic_object2.property 1)
}
}
EDIT: Given your newly posted code, you may even simply wish to use an common interface, or base class, for the dynamic objects.
Interface:
public interface CommonInterface {
boolean isValid();
void method1();
void method2();
void method3();
}
Class Example:
public Class1 implements CommonInterface {
public boolean isValid() {
return true;
}
public void method1() {
System.out.println("Method 1");
}
public void method2() {
System.out.println("Method 2");
}
public void method3() {
System.out.println("Method 2");
}
}
Code:
public void doSomethingWithCommonObjects(CommonInterface object) {
object.method1();
if (object.isValid()) {
object.method2();
} else {
object.method3();
}
}
Each of the dynamic objects simply need to implement the CommonInterface interface, which would enforce method1(), method2(), method3() and property1() signatures for each object to implement.
Previous answer details for reference:
You will either have to use Java Generics, potentially with some common interface or base class for the objects in question so that you can then call their methods.
E.g.
public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
T max = x; // assume x is initially the largest
if (y.compareTo(max) > 0) {
max = y; // y is the largest so far
}
if (z.compareTo(max) > 0) {
max = z; // z is the largest now
}
return max; // returns the largest object
}
If, however, you require to call particular methods without knowing the interface for those methods beforehand programmatically, then you're into Reflection territory.
I am way over thinking this: What I am trying to do is [hopefully not reinvent the wheel and] come up w/ a [Android] Java eventing mechanism that allows subclasses to pre-define an arbitrary set of "features" with getters and setters that fire individual callbacks.
I think I am fusioning some combination of Command, Visitor, Decorator, Facade and Observer patterns here, and confusing myself along the way.
I have been programming for well over 20 years, but I feel like a n00b on this fairly simple problem! :(
I have searched SO for the compiler error and read many of the results, but I still haven't found a solution that works for me.
(How to make a Java class that implements one interface with two generic types? seems to be the most relevant one that I have found, but I also want to generically get the values and fire events to callbacks when they are set).
First, let the below mostly valid code speak for itself...
interface IFeature
{
}
interface IFeatureCallbacks<T extends IFeature>
{
boolean onChanged(Feature<T> c);
}
public static class Feature<T extends IFeature>
{
private Set<IFeatureCallbacks<T>> listeners = new LinkedHashSet<>();
public void addListener(IFeatureCallbacks<T> listener)
{
listeners.add(listener);
}
public void removeListener(IFeatureCallbacks<T> listener)
{
listeners.remove(listener);
}
protected void onChanged()
{
for (IFeatureCallbacks<T> listener : listeners)
{
listener.onChanged(this);
}
}
}
//
interface IFeatureA
extends IFeature
{
int getA();
}
interface IFeatureACallbacks
extends IFeatureCallbacks<IFeatureA>
{
}
public static class FeatureA
extends Feature<IFeatureA>
implements IFeatureA
{
private int a;
public void setA(int value)
{
a = value;
onChanged();
}
#Override
public int getA()
{
return a;
}
}
//
interface IFeatureB
extends IFeature
{
boolean getB();
}
interface IFeatureBCallbacks
extends IFeatureCallbacks<IFeatureB>
{
}
public static class FeatureB
extends Feature<IFeatureB>
implements IFeatureB
{
private boolean b;
public void setB(boolean value)
{
b = value;
onChanged();
}
#Override
public boolean getB()
{
return b;
}
}
//
interface IDeviceWithFeatureA
extends IFeatureA
{
}
interface IDeviceWithFeatureACallbacks
extends IFeatureACallbacks
{
}
public static class DeviceWithFeatureA
extends Feature<IDeviceWithFeatureA>
implements IDeviceWithFeatureA
{
FeatureA a = new FeatureA();
public void addListener(IDeviceWithFeatureACallbacks listener)
{
a.addListener(listener);
}
public void setA(int value)
{
a.setA(value);
}
#Override
public int getA()
{
return a.getA();
}
}
//
interface IDeviceWithFeatureB
extends IFeatureB
{
}
interface IDeviceWithFeatureBCallbacks
extends IFeatureBCallbacks
{
}
public static class DeviceWithFeatureAB
extends Feature<IDeviceWithFeatureB>
implements IDeviceWithFeatureB
{
FeatureB b = new FeatureB();
public void addListener(IDeviceWithFeatureBCallbacks listener)
{
b.addListener(listener);
}
public void setB(boolean value)
{
b.setB(value);
}
#Override
public boolean getB()
{
return b.getB();
}
}
The above code seems to work fine, albeit something about it smells a bit off.
The problem is when I try to do this:
interface IDeviceWithFeatureAAndFeatureB
extends IFeatureA, IFeatureB
{
}
/*
Compiler error:
'IFeatureCallbacks' cannot be inherited with different type arguments 'IFeatureA' and 'IFeatureB'
*/
interface IDeviceWithFeatureAAndFeatureBCallbacks
extends IFeatureACallbacks, IFeatureBCallbacks
{
}
public static class DeviceWithFeatureAB
extends Feature<IDeviceWithFeatureAAndFeatureB>
implements IDeviceWithFeatureAAndFeatureB
{
FeatureA a = new FeatureA();
FeatureB b = new FeatureB();
public void addListener(IDeviceWithFeatureAAndFeatureBCallbacks listener)
{
a.addListener(listener);
b.addListener(listener);
}
public void setA(int value)
{
a.setA(value);
}
#Override
public int getA()
{
return a.getA();
}
public void setB(boolean value)
{
b.setB(value);
}
#Override
public boolean getB()
{
return b.getB();
}
}
I am less interested in trying to figure out how to make what I am trying to do compilable, and I am more interested in what about my abuse of a pattern is way off base so that I can re-write it to be both simpler and compile.
You are abusing the basic "pattern" of OOP -- inheritance. The adage is that "favor composition over inheritance". Think in terms of "contains", instead of "is-a".
Take Zoo for example. A zoo is just a bunch of animals, right? So naturally, we may want to declare Zoo as subtype of Set<Animal>. Perhaps even have class Zoo extends HashSet<Animal>.
However, that is likely a wrong design. A zoo is actually a lot of things. It contains a set of animals, sure; but it also contains a set of people (as workers, not exhibits (although...) ). So it's better to
class Zoo
Set<Animal> animals(){ ... }
Set<Person> workers(){ ... }
Anywhere we need to treat a zoo as a set of animals, just use zoo.animals(); think of it as a type cast, or projection. We don't need inheritance here.
In your design, you have too many types; what's worse, too many type relationships. It seems that you simply need one generic class that reads/writes value of T, and contains listeners of T
class Feature<T>
T value;
// getter
// setter
Set<ChangeListener<T>> listeners;
interface ChangeListener<T>
void onChange(T oldValue, T newValue)
A device contains a bunch of features
class SomeDevice
Feature<Integer> featureA = new Feature<>();
Feature<Boolean> featureB = new Feature<>();
That's it. You can operate on feature A of the device by operating on itsfeatureA.
I've been dealing with a domain issue where I have classes that implement a common interface and I want to be able to get hashes from these objects differently depending on if the object is accessed as an interface or as a concrete class instance. Basically what I want is the following:
public class A implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int Bar.hashCode(){ return 123;}
}
public class B implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int Bar.hashCode(){ return 123;}
}
public class C implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int Bar.hashCode(){ return 123;}
}
Bar interfaceObject = new A();
interfaceObject.hashCode(); //return 123
Bar aObject = new A();
aObject.hashCode();// return 1
As far as I know there isn't a way to do this, and I can think of lots of reasons why this could cause issues, but I wanted to ask those smarter than I if they had any nice ways of doing this outside of making the interface have a function like public int getCustomHashCodeForJustThisInterface(). I like being able to use these objects in hashMaps without having to jump through hoops, but with their current implementation of hashCode they would break, since these objects can have multiple views of their identity depending on how they are used, and I don't want to change their base implementation of hashCode;
You can't do that, because Java does not support non-polymorphic instance methods (static methods are not polymorphic, as the previous answer showed).
What you can do is to make your classes not directly implement Bar, but another interface (e.g. BarProvider) with a toBar() or getBar() method, which returns a custom object of type Bar, which behaves as you want.
public class A implements BarProvider{
#Override
public int hashCode(){ return 1;}
#Override
public Bar toBar() {
return new Bar() {
#Override
public int hashCode() { return 123; }
};
}
}
A aObject = new A();
interfaceObject.hashCode(); //return 1;
Bar interfaceObject = aObject.toBar();
interfaceObject.hashCode(); // return 123
Several improvements are possible, such as having the Bar object stored as a final field (to avoid multiple initializations), and having a reverse reference that allows you to get back from the Bar to its BarProvider.
Another possibility is to use an external provider, that makes your computations
public class A implements Bar{
#Override
public int hashCode(){ return 1;}
}
public final class BarHasher implements Hasher<Bar> }
#Override
public int hashFor(Bar object) { return 123; }
}
A aObject = new A();
interfaceObject.hashCode(); //return 1;
BarHasher.hashFor(aObject); // return 123
or a static method that calls some other method
public class A implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int hashAsBar() { return 123; }
}
public interface BarHasher implements Hasher<Bar> {
#Override
public int hashFor(Bar object) { return object.hashAsBar(); }
}
A aObject = new A();
interfaceObject.hashCode(); //return 1;
BarHasher.hashFor(aObject); // return 123
In case you don't know it, what you're trying to do is possible (and it's the default behavior) in C++ (you must declare methods as virtual to have the same behavior as Java) and in C# (but you will have a warning, unless you use the modifier new on the overriding method)
There's no way to do this that I know of.
Here's something you can do that you may not have known of (I'm not suggesting this is a good idea):
package com.sandbox;
import java.io.IOException;
public class Sandbox {
public static void main(String[] args) throws IOException {
A.speak();
B.speak();
A a = new A();
a.speak(); //my ide rightly gives a warning here. static function accessed through instance
A b = new B();
b.speak(); //my ide rightly gives a warning here. static function accessed through instance
}
public static class A {
public static void speak() {
System.out.println("A");
}
}
public static class B extends A {
public static void speak() {
System.out.println("B");
}
}
}
This will print:
A
B
A
A
Just to reiterate: This is NOT a good idea. I'm just letting you know for educational purposes.
It's easy to invoke different methods based on the declared type of a variable. That's called overriding, and here's an example of it:
public class Example {
public static void main(String[] argv) throws Exception {
Integer v1 = 12;
Number v2 = v1;
System.out.println(v1.hashCode() + " -> " + new KeyWrapper(v1).hashCode());
System.out.println(v2.hashCode() + " -> " + new KeyWrapper(v2).hashCode());
}
private static class KeyWrapper {
private Object obj;
private int hash;
public KeyWrapper(Integer v) {
this.hash = v.hashCode() * 3;
}
public KeyWrapper(Number v) {
this.hash = v.hashCode() * 5;
}
#Override
public int hashCode() {
return hash;
}
}
}
When you run this, you get the following output:
12 -> 36
12 -> 60
Why this is a bad idea is that you can't implement equals() in in a way that preserves its contract (which is that two equal objects must have equal hashcodes). At compile-time you have information about how the values are referenced, but at runtime you only know what they are.
That said, if you want to use different hashcode calculations for objects that do implement an interface, versus those that don't, you can write a KeyWrapper that uses instanceof.
public class Example {
public static void main(String[] argv) throws Exception {
Integer v1 = 12;
String v2 = "foo";
System.out.println(v1.hashCode() + " -> " + new KeyWrapper(v1).hashCode());
System.out.println(v2.hashCode() + " -> " + new KeyWrapper(v2).hashCode());
}
private static class KeyWrapper {
private Object wrapped;
public KeyWrapper(Object obj) {
this.wrapped = obj;
}
#Override
public boolean equals(Object obj) {
return wrapped.equals(obj);
}
#Override
public int hashCode() {
return (wrapped instanceof Number) ? wrapped.hashCode() * 3 : wrapped.hashCode() * 5;
}
}
}
This, of course, doesn't care about the declared type of the variable, only its actual type.
I have
public enum BaseActions implements Actions{
STAND (0,0,0),
TURN (1,1,1);
//other stuff
}
public enum CoolActions implements Actions{
STAND (0,2,3),
TURN(1,6,9);
//other stuff
}
public enum LooserActions implements Actions{
STAND (0,-2,-3),
TURN(1,-6,-9);
//other stuff
}
public interface Actions {
//interface methods
}
class A {
Actions mCurrentAction;
protected void notifyNewAction(final Actions pAction, final Directions pDirection){
//body of the method
}
public void doStuff(final Actions pAction) {
if(pAction.getMyId() > 0)
notifyNewAction(BaseActions.STAND, myDirection);
else
notifyNewAction(BaseActions.TURN, myDirection);
}
}
class B extends A{
public void doMyStuff() {
doStuff(CoolActions.STAND);
}
}
class C extends A{
public void doMyStuff() {
doStuff(LooserActions.STAND);
}
}
i would like to make A use CoolActions when doStuff is called from B and LooserActions when called from C.
One of the ways i think i can do it is to use generics, and then in B and C use
doStuff<CoolActions>(CoolActions.STAND)
and have in A
public void doStuff<T extends EnumActions&Actions>(final Actions pAction) {
if(pAction.getMyId() > 0)
notifyNewAction(T.STAND, myDirection);
else
notifyNewAction(T.TURN, myDirection);
}
where EnumActions is a base enum that just contains the declaration of the enum's elements, and nothing more, something like an interface for enums, but enums can't extend another class since they already extends Enum, and an interface can't provide what i mean.
Another way would be to make the enums implements a EnumActions interface that has
public interface EnumActions {
public <T> T getStand();
public <T> T getTurn();
}
and have
class A {
Actions mCurrentAction;
protected void notifyNewAction(final Actions pAction, final Directions pDirection){
//body of the method
}
public <T implements EnumActions> void doStuff(final Actions pAction) {
if(pAction.getMyId() > 0)
notifyNewAction(T.getStand(), myDirection);
else
notifyNewAction(T.getTrun(), myDirection);
}
}
and
public enum CoolActions implements Actions, EnumActions{
STAND (0,2,3),
TURN(1,6,9);
public CoolActions getStand();
public CoolActions getTurn();
//other stuff
}
class B extends A{
public void doMyStuff() {
doStuff<CoolActions>(CoolActions.STAND);
}
}
But 1)i don't know if it would work 2) I lose the advanteges of using enums 3) this seams a really bad way to handle this 4) i would have to write a lot( X enum fields per Y different enums). I changed from static final fields to enum to improve readability and order, and this seams to make things even harder.
Am i designing this in the wrong way? How can i handle this?
Is there a preferred way to solve this problem?
Thanks
It seems like enums add nothing and are not going to do what you want. Maybe you should just use a normal class hierarchy - make BaseActions, CoolActions and LooserActions just classes that implement Actions and STAND and TURN methods in those classes.
it's ugly, but it may do what you want:
interface Actions {
int getMyId();
}
enum BaseActions implements Actions {
STAND(0, 0, 0), TURN(1, 1, 1);
BaseActions(int x, int y, int z) {}
#Override public int getMyId() {
return 0;
}
}
enum CoolActions implements Actions {
STAND(0, 2, 3), TURN(1, 6, 9);
CoolActions(int x, int y, int z) {}
#Override public int getMyId() {
return 0;
}
}
enum LooserActions implements Actions {
STAND(0, -2, -3), TURN(1, -6, -9);
LooserActions(int x, int y, int z) {}
#Override public int getMyId() {
return 0;
}
}
class Directions {}
class A {
Actions mCurrentAction;
protected void notifyNewAction(final Actions pAction, final Directions pDirection) {
System.out.println(pAction+" "+pAction.getClass());
}
public void doStuff(final Actions pAction) {
Directions myDirection = null;
Enum e=(Enum)pAction;
if(e instanceof CoolActions)
e=CoolActions.valueOf(e.name());
else if(e instanceof LooserActions)
e=LooserActions.valueOf(e.name());
if (pAction.getMyId() > 0) notifyNewAction((Actions)e, myDirection);
else
notifyNewAction((Actions)e, myDirection);
}
}
class B extends A {
public void doMyStuff() {
doStuff(CoolActions.STAND);
}
}
class C extends A {
public void doMyStuff() {
doStuff(LooserActions.STAND);
}
}
public class Main {
public static void main(String[] args) {
A a = new A();
a.doStuff(BaseActions.STAND);
B b = new B();
b.doMyStuff();
C c = new C();
c.doMyStuff();
}
}