iamMobile iamMobile -4 years ago 67
Java Question

Effective design for related classes that use unrelated classes

I have following situation and would like to know the best way to design my solution

public abstract class A {
public abstract A getHelper();
public abstract void launchHandle();
public static A initHelper(String condition) throws Exception {
if ( condition == 'xyz') {
return C.getHelper();
} else {
return B.getHelper();
}
}
}

public class B extends A {
protected static A b;

@Override
public A getHelper() {
b = new B();
return b;
}

@Override
public void launchHandle() {
System.out.println("Launching Handle");
}

public String getName() {
return "I am from Class B";
}
}

public class C extends A {
protected static A c;

@Override
public A getHelper() {
c = new C();
return c;
}

@Override
public void launchHandle() {
System.out.println("Launching Handle from C");
}

public String getValue() {
return "I am from Class C";
}
}

**Executor class**

public class Executor {

public static void main(String[] args) {
A aa = a.initHelper(condition);
}
}


Now in the above approach, i am unable to access methods like aa.getName() from Class B OR aa.getValue() from Class C, which makes sense. However how to get these methods in executor class? Executor does not know anything about Class B & C and should not know. Executor is only aware of Class A, but want to access methods SubClass methods from B & C which are extended from Class A.

Please help design this and what could be best way to solve this.

Thanks in advance.

Answer Source

Executor is only aware of Class A, but want to access methods SubClass methods from B & C which are extended from Class A.

If you take a closer look at your code, you will notice that the only contract constant across all your classes is the launchHandle method (baring getHelper and initHelper which are simply used for instantiating the right subclass). There is no real relation between B and C other than the fact that their instantiation is controlled by A.

This is how I would consider approaching the problem :

Executor Factory

Make Executor an abstract class rather than making it the entry point of your program :

public abstract class Executor {
    public abstract void performTask();
    public static void execute(String condition) {
       Executor executor = null;
       if ( condition.equals("xyz")) {
          executor = new AExector();
       } else {
          executor = new BExecutor();
       }
       executor.performTask();
    }

}

Executor implementations

Create a different implementation for operating on B called BExecutor :

public class BExecutor extends Executor {

    public void performTask() {
      System.out.println("launching handle from B");
      //create or get data to perform the task on
      B b = new B();
      String name = b.getName();
      System.out.println("I am from "+name);

    }
}

Create a different implementation for operating on C called CExecutor :

public class CExecutor extends Executor {


    public void performTask() {
      System.out.println("launching handle from C");
       //create or get data to perform the task on
      C c = new C();
      String value = c.getValue();
      System.out.println("I am from "+value);

    }
}

Your main method can then look like this :

public static void main(String []args) { 
   Executor executor = Executor.execute(condition);
}

And for some reason, if you do find some common contract between B and C, you an always create an interface which both B and C can implement and use a reference of this interface instead of using a B or C reference.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download