Refactoring code in Java, alternatives to large if statement - java

I'm refactoring some code in a project I'm working on and I ran into a large if/else if statement that follows the format:
if (changer instanceof AppleChanger)
{
panel = new ApplePanel();
}
else if (changer instanceof OrangeChanger)
{
panel = new OrangePanel();
}
Now my first impulse was to refactor it using polymorphism to have it appear like
panel = changer.getChangerPanel();
However unfortunately the class package doesn't have access to the panel package.
My next impulse was to create a PanelChooser class with an overloaded method:
PanelChooser.getPanel(changer);
//Overloaded Method
public Panel getPanel(OrangeChanger changer)
{
Panel orangePanel = new OrangePanel();
return orangePanel;
}
public Panel getPanel(AppleChanger changer)
{
Panel applePanel = new ApplePanel();
return applePanel;
}
Is this a good solution or is there a better way to solve this?

The fundamental 'problem' here is that you have parallel class hierarchies. You're not going to be able to replace that if statement without some fairly heavy refactoring. Some suggestions are on c2 wiki.
The best you can do, and possibly a perfectly fine solution, is to move the if statement into a 'factory' class and make sure it's not duplicated anywhere else.

I think its good that your first impulse didn't work :) Otherwise you would couple you changer code (which should be something about logic) to UI code (panel) and its wrong.
Now I can offer you the following solution:
create an interface PanelCreator with method Panel createPanel like this:
interface PanelCreator {
Panel createPanel();
}
Now, provide 2 implementations:
public class OrangePanelCreator implements PanelCreator{
Panel createPanel() {
return new OrangePanel();
}
}
public class ApplePanelCreator implements PanelCreator {
Panel createPanel() {
return new ApplePanel();
}
}
And now come the interesting part:
Create a Map, PanelCreator> this would act like a registry for your panels:
Map<Class<Changer>, PanelCreator> registry = new HashMap<>;
registry.put(OrangeChanger.class, new OrangePanelCreator());
registry.put(AppleChanger.class, new ApplePanelCreator());
And in your code now you can do the following thing:
panel = registry.get(changer.getClass()).createPanel();
I think it will be more elegant since you can easily change implementations of creators given the changer.
Hope this helps

If there is more than one of this if/else constructs in the code dependending on the instance type of a Changer, you can use the visitor pattern like this:
public interface ChangerVisitor {
void visit(OrangeChanger changer);
void visit(AppleChanger changer);
...
}
public class ChangerVisitorEnabler<V extends ChangerVisitor> {
public static <V extends ChangerVisitor> ChangerVisitorEnabler<V> enable(V) {
return new ChangerVisitorEnabler<V>(visitor);
}
private final V visitor;
private ChangerVisitorEnabler(V visitor) {
this.visitor = visitor;
}
public V visit(Charger changer) {
if (changer instanceof OrangeChanger) {
visitor.visit((OrangeChanger)changer);
} else if (changer instanceof AppleChanger) {
visitor.visit((AppleChanger)changer);
} else {
throw new IllegalArgumentException("Unsupported charger type: " + changer);
}
return visitor;
}
}
Now you have a single type check code block and a type safe interface:
public PanelChooser implements ChangerVisitor {
public static Panel choosePanel(Changer changer) {
return ChangerVisitorEnabler.enable(new PanelChooser()).visit(changer).panel;
}
private Panel panel;
private PanelChooser() {
}
void visit(OrangeChanger changer) {
panel = orangePanel();
}
void visit(AppleChanger changer) {
panel = applePanel();
}
}
The usage is very simple:
panel = PanelChooser.choosePanel(chooser);

Perhaps you can do:
public Panel getPanel(Changer changer)
{
String changerClassName = changer.class.getName();
String panelClassName = changerClassName.replaceFirst("Changer", "Panel");
Panel panel = (Panel) Class.forName(panelClassName).newInstance();
return panel;
}
I don't program in Java, but that is what I would try if this were in C#. I also don't know if this would work with your packages.
Good luck!

I don't see enough existing code and design at whole. So probably, first of all I would try to move the code with panel instantiation to the same place where Changer instance is created. Because choosing a Panel is the same decision as choosing a Changer.
If a selected Changer is dynamically selected, you may just create these panels and then show/hide them accordingly.

I'd do the following:
Have an interface PanelChooser with a single method returning a Panel for a Changer.
Have an implementation ClassBasedPanelChooser returning a panel when the Change implements a certain class and null otherwise. The class and the panel to be returned get passed in in the constructor.
Have another implementation CascadingPanelChooser which takes a list of PanelChoosers in the constructor arguments and on call of its method asks each PanelChooser to provide a panel until it receives a not null panel, then it returns that panel.

Your solution will not work, because Java selects the method based on the compiletime type (which here is probably Changer). You could use a Map<Class<? extends Changer>, Panel> (or Map<Class<? extends Changer>, Class<? extens Panel>> if you need to create new instances every time). This solution does require extra work if you need this to work for - yet unknown - subclasses of for example OrangeChanger.
eg for a single instance per Changer subclass
changerToPanel.get(changer.getClass());
or if you need new instances:
changerToPanelClass.get(changer.getClass()).newInstance();
The other option would be to go for your initial hunch, and make Changer know about Panel.

Take a look at the Factory and Abstract Factory Patterns.
The Factory Pattern is a creational pattern as it is used to control class instantiation. The factory pattern is used to replace class constructors, abstracting the process of object generation so that the type of the object instantiated can be determined at run-time.
Abstract Factory Pattern is a creational pattern, as it is used to control class instantiation. The abstract factory pattern is used to provide a client with a set of related or dependent objects. The family of objects created by the factory is determined at run-time according to the selection of concrete factory class.

Do not use instanceof.Why polymorphism fails
The only place to use instanceof is inside equals method.
To answer your question. Follow this link.
Credits to Cowan and jordao .
Using Reflection.
public final class Handler {
public static void handle(Object o) {
for (Method handler : Handler.class.getMethods()) {
if (handler.getName().equals("getPanel") &&
handler.getParameterTypes()[0] == o.getClass()) {
try {
handler.invoke(null, o);
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
throw new RuntimeException("Can't handle");
}
public static void handle(Apple num) { /* ... */ }
public static void handle(Orange num) { /* ... */ }
Chain of Responsibility
public abstract class Changer{
private Changer next;
public final boolean handle(Object o) {
boolean handled = doHandle(o);
if (handled) { return true; }
else if (next == null) { return false; }
else { return next.handle(o); }
}
public void setNext(Changer next) { this.next = next; }
protected abstract boolean doHandle(Object o);
}
public class AppleHandler extends Changer{
#Override
protected boolean doHandle(Object o) {
if (!o instanceof Apple ) {
return false;
}
OrangeHandler.handle((Orange) o);
return true;
}
}

Related

How to create a new object based on interface implementation

Firstly, I believe my question is badly worded but don't really understand how to phrase it.
I have a starting interface that is being implemented by a number of classes. What I want to do is to see if there is a way to create a new object such that I am being passed the generic interface, then based on the method .getClass().getSimpleName(), create a new object based on that string.
Is the only way to create a switch case statement? As the number of implementing classes are too many (about 100 or so).
Reference code:
public interface MyInterface {
public void someMethod();
}
then I would have my implementing classes:
public class MyClass1 implements MyInterface {
public void someMethod() { //statements }
}
public class MyClass2 implements MyInterface {
public void someMethod() { //statements }
}
public class MyClass3 implements MyInterface {
public void someMethod() { //statements }
}
What I want to have in the end is another class which is passed an argument of type MyInterface, get the simple name from that and create a new instance of MyClassX based on that simple name.
public class AnotherClass {
public void someMethod(MyInterface interface) {
if (interface == null) {
System.err.println("Invalid reference!");
System.exit(-1);
} else {
String interfaceName = interface.getClass().getSimpleName();
/**
* This is where my problem is!
*/
MyInterface newInterface = new <interfaceName> // where interfaceName would be MyClass1 or 2 or 3...
}
}
}
Any help is highly appreciated!
You can use reflection for this:
public void someMethod(MyInterface myInterface) {
Class<MyInterface> cl = myInterface.getClass();
MyInteface realImplementationObject = cl.newInstance(); // handle exceptions in try/catch block
}
This is a common problem with many solutions. When I face it, I never use reflection because it is difficult to maintain if it is part of a big project.
Typically this problem comes when you have to build an object based on a user selection. You can try a Decorator pattern for that. So, instead of building a different object for each option. You can build a single object adding functionality depending on a selection. For instance:
// you have
Pizza defaultPizza = new BoringPizza();
// user add some ingredients
Pizza commonPizza = new WithCheese(defaultPizza);
// more interesting pizza
Pizza myFavorite = new WithMushroom(commonPizza);
// and so on ...
// then, when the user checks the ingredients, he will see what he ordered:
pizza.ingredients();
// this should show cheese, mushroom, etc.
under the hood:
class WithMushroom implements Pizza {
private final Pizza decorated;
public WithMushroom(Pizza decorated) {
this.decorated = decorated;
}
#Override
public Lizt<String> ingredients() {
List<String> pizzaIngredients = this.decorated.ingredients();
// add the new ingredient
pizzaIngredients.add("Mushroom");
// return the ingredients with the new one
return pizzaIngredients;
}
}
The point is that you are not creating an object for each option. Instead, you create a single object with the required functionality. And each decorator encapsulates a single functionality.

Java object type represented by variable

How can i represent an object type with a variable such as a string. For example I have DrawPanel1, DrawPanel2, DrawPanel3, all the way through DrawPanel12.
and in a separate class I have a method to create each one with "DrawPanel1 panel = new DrawPanel1();" but I want to have a method.
public void TestPanel(int panelNum){}
where it so it creates DrawPanel(panelNum), so if 2 is passed in it creates a new DrawPanel2.
I thought of doing this with [ String Panel = ("DrawingPanel"+panelNum); ]
but when I used Panel rather than the name of the object it wouldn't work.
I think I understand what you are asking, and I'm going to provide an answer to your immediate question. What you are attempting sounds a little over-complicated, however. The following may need a bit of tweaking...
public void testPanel(Class<?> clazz) {
Object instance = Class.forName(class.getName());
...
}
At this point, instance won't do you much good. You could also create an interface DrawPanelI with the methods used by your different DrawPanel's and have each of them implement that interface. Then, change Object instance to DrawPanelI instance. Now, you can invoke the common methods through instance.
It is a very time consuming task to have variables DrawPanel1 - DrawPanel12. Instead, it would be much easier to have a list of them.
//Making the list
List<DrawPanel> drawPanels = new ArrayList<DrawPanel>();
//Adding to the list
drawPanels.add(new DrawPanel());
//Retrieving from the list
DrawPanel panel = drawPanels.get(0);//"DrawPanel1"
//Processing the list
for (DrawPanel panel: drawPanels){
panel.doStuff();
}
Assuming there is a DrawPanel interface then it would be possible to use a factory pattern:
public class DrawPanelFactory() {
public DrawPanel create(int whichTypeOfPanel) {
if (whichTypeOfPanel == 1) {
return new DrawPanel1();
}
...
if (whichTypeOfPanel == 12) {
return new DrawPanel12();
}
throw new IllegalArgumentException("Unsupported panel type:" + whichTypeOfPanel);
}
}
That ends up being a lot of if statements, but still easily testable. To avoid the if statements use a static Map<Integer, DrawPanelFactoryDelegate> to associate a specific integer value with a specific factory that knows how to create that specific type of DrawPanel:
public class DrawPanelFactory() {
private static Map<Integer, DrawPanelFactoryDelegate> drawPanelFactories = new ...;
static {
drawPanelFactories.put(1, new DrawPanelFactory1());
...
drawPanelFactories.put(12, new DrawPanelFactory12());
}
public DrawPanel create(int whichTypeOfPanel) {
DrawPanelFactoryDelegate delegateFactory = drawPanelFactories.get(whichTypeOfPanel);
if (delegateFactory != null) {
return delegateFactory .create();
}
throw new IllegalArgumentException("Unsupported panel type:" + whichTypeOfPanel);
}
}
interface DrawPanelFactoryDelegate {
public DrawPanel create();
}
DrawPanel1Factory implements DrawPanelFactoryDelegate {
public DrawPanel create() {
return DrawPanel1();
}
}
...
DrawPanel12Factory implements DrawPanelFactoryDelegate {
public DrawPanel create() {
return DrawPanel12();
}
}
then in use:
DrawPanelFactory drawPanelFactory = new DrawPanelFactory();
DrawPanel aDrawPanel = drawPanelFactory.create(1);
...
DrawPanel yetAnotherDrawPanel = drawPanelFactory.create(12);

Java Generics - Iterating with upper bounded and lower bounded wildcards

I have 2 Interfaces:
public interface Flash { public void flash(int level); } and
public interface SuperFlash extends Flash { public void flash(int level, boolean repeat); }
Then I have a custom collection class which should hold any number of things implementing Flash or SuperFlash. The class declaration looks something like
public class FlashyThings<? extends Flash>.
So the class can hold instances of type Flash and its subtype(s).
Inside the class FlashyThings, I am using an ArrayList to hold all of these objects:
private ArrayList<? extends Flash> things;
So far so good, now, when I try to iterate over the collection, is there a way to know/infer the dynamic type of the objects without using instanceof (as in the next snippet)?
for (Flash f : this.things) {
if (f instanceof SuperFlash) { // <-- :(
// SuperFlash things
} else {
// Flash things
}
}
This is the upper bounded side of the medal, now to the lower bounded side
To begin with, I had to change the class declaration to
public class FlashyThings
as lower bounded wildcards are not allowed in the class declaration. The ArrayList declaration now looks like:
private ArrayList<? super SuperFlash> things;
Now iterating over the collection becomes:
for (Object o : this.things) { // <-- :((
// All things are of type Object which is *really* not cool
if (o instanceof SuperFlash) { // <-- :(
// SuperFlash things
} else {
// Flash things
}
}
So I'm pretty much stuck where I began.
What would be the recommended way to iterate over such a construct? To summarise, what I want to achieve having is
the interface hierarchy described at the very top
the class FlashyThings being parameterisable
iterating over the ArrayList things, taking into account the dynamic type of its contents (without having to do the instanceof check)
What you need to do is create an abstract FlashyThing that does as much of the shared methods as possible in the abstract class, leaving only the stuff that is dependent on knowing you have a Flash or SuperFlash to the subclass. For example (publics and privates left out for brevity):
abstract class AbstractFlashyThing<F extends Flash> {
List<F> flashes;
AbstractFlashyThing() {
flashes = new ArrayList<F>();
}
void doOperations() {
for (F flash : flashes) {
doOperation(flash);
}
}
abstract void doOperation(F flash);
}
Note how the generic type F is used as a place holder wherever possible.
Example subclass
class SuperFlashyThing extends AbstractFlashyThing<SuperFlash> {
#Override
void doOperation(SuperFlash superFlash) {
// do super flash stuff
}
}
Subclass is a concrete implementation rather than a generic class, so its instatiation is as follows.
SuperFlashyThing thing = new SuperFlashyThing();
// as opposed to the following
SuperFlashyThing<SuperFlash> thing = new SuperFlashyThing<SuperFlash>();
Maybe I don't quite understand the problem, but why are you making everything so complicated, instead of just using polymorphism? This is what the Object Oriented Paradigm is designed to do. Example:
Flash.java
public class Flash {
public void doSomething() {
System.out.println("Flash doSomething()");
}
}
SuperFlash.java
public class SuperFlash extends Flash {
#Override
public void doSomething() {
System.out.println("SuperFlash doSomething()");
}
}
FlashyThings.java
public class FlashyThings {
private ArrayList<Flash> things = new ArrayList<>();
public ArrayList<Flash> getThings() {
return things;
}
public void doSomething(){
for (Flash thing : things) {
thing.doSomething();
}
}
}
ExampleMain.java
public class ExampleMain {
public static void main(String[] args) {
Flash first = new Flash();
SuperFlash second = new SuperFlash();
Flash third = new Flash();
FlashyThings things = new FlashyThings();
things.getThings().add(first);
things.getThings().add(second);
things.getThings().add(third);
things.doSomething();
}
}
What about using an enum ?
public enum FlashType
{
Flash, SuperFlash;
}
Add a method for checking the flash type of any object of type Flash:
public interface Flash
{
void flash(int level);
FlashType getType();
}
Then iterate over private ArrayList<? extends Flash> things;
for (Flash f : this.things)
{
if (f.getType() == FlashType.SuperFlash)
{
// SuperFlash things
}
else if (f.getType() == FlashType.Flash)
{
// Flash things
}
}
or iterate over ArrayList<? super SuperFlash> things;
for (Object o : this.things)
{
final Flash f = (Flash)o;//this cannot failed: SuperFlash extends Flash
if (f.getType() == FlashType.SuperFlash)
{
// SuperFlash things
}
else if (f.getType() == FlashType.Flash)
{
// Flash things
}
}

How can I compare objects using instanceof but Interface types (not passing exact class name.)

public interface Component{}
public class AppManager {
public void doWork(){
SomeComponent comp = new SomeComponent ();
AddComponentToList(comp);
}
public void AddComponentToList(Component compo){
componentList.add(compo);
}
/* Give me the component I want. */
public Component getComponent(Component comp){
for (Component component : getComponentList()) {
if (component instanceof comp) {
return component;
}
}
}
private ArrayList<Component> componentList = new ArrayList<Component>();
}
public class SomeComponent implements component {
public void MyMethod() {
appManager.getComponent(SomeComponent );
}
public void setAppMnger(AppManager appm){
this.appManager = appm;
}
private AppManager appManager ;
}
In Above code AppMnger is having a list of components. Components are communicating each other. So if one component want to know another component instance it call the AppMnger getComponent(comp) method. But I get an error when I use instanceof operator. I don't want each component to want compare the list but I want to delegate that task to AppMnger because he is the one who knows about components it created.
Amy thought?
I think you should redesign getComponent to take a Class<? extends Component> rather than a Component. Then you can use isInstance:
public Component getComponent(Class<? extends Component> componentClass) {
for (Component component : getComponentList()) {
if (componentClass.isInstance(component)) {
return component;
}
}
return null; // Or throw an exception, potentially.
}
And SomeComponent would use:
appManager.getComponent(SomeComponent.class);
If you really wanted to use an instance, you could overload the method like this:
public Component getComponent(Component existingComponent) {
return getComponent(existingComponent.getClass());
}
EDIT: If you actually only want to check for the exact class, you don't want instanceof-like behaviour - you just want:
public Component getComponent(Class<? extends Component> componentClass) {
for (Component component : getComponentList()) {
if (componentClass == component.getClass()) {
return component;
}
}
return null; // Or throw an exception, potentially.
}
I would still suggest using this method signature though - it would feel very odd to have to already have an instance of a component in order to find a component of the type you want.
If you want the class to match exactly (List != ArrayList) then use this:
if (comp.getClass().equals(component.getClass())) ...
If you want it to work exactly like instanceof (List => ArrayList) then you can try this:
if (comp.getClass().isInstance(component)) ...
I guess previous answers by Black,max and Jon are sufficient enough for your comparison part , for the "I don't want each component to want compare the list but I want to delegate that task to AppMnger because he is the one who knows about components it created. Amy thought?" you can try using the visitor design pattern .

Downcasting and polymorphism without using instanceof? (Java)

Here's the sort of thing I'm trying to do:
class Foo {
private ArrayList<Widget> things; //Contains WidgetA, WidgetB and WidgetAB objects
//...
void process(int wIndex) {
process(things.get(wIndex);
}
private void process(WidgetA w) {
//Do things
}
private void process(WidgetB w) {
//Do other things
}
private void process(WidgetAB w) {
//Do completely different things
}
}
abstract class Widget {
//...
}
class WidgetA extends Widget {
//...
}
class WidgetB extends Widget {
}
class WidgetAB extends WidgetA {
}
Basically, a separate class gets an array index from user input, and passes it to the process(int) method, which is supposed to kick off a type-specific process() method to process the object at the passed index. The problem is that the objects are treated as Widget objects, not WidgetA, etc. I could loop through the types using instanceof, I guess, but I'm trying to avoid using that.
The logic in the process() methods needs to access private fields in the Foo class, so moving them to the Widget subclasses might not be the best idea.
So the question is, is there a way for the correct process() method to be called for a given Widget subtype, without using instanceof?
Yes, have a look at the Visitor pattern - also known as double dispatch.
Another potential solution is to use Java's reflection API's. Example:
class Foo {
private ArrayList<Widget> things; //Contains WidgetA, WidgetB and WidgetAB objects
//...
void process(int wIndex) {
Widget theWidget = things.get(wIndex);
try {
Class type = theWidget.getClass();
Class[] arg_types = new Class[]{type};
this.getMethod("process", arg_types).invoke(this, theWidget);
} catch (Exception e) {
//Could be SecurityException or NoSuchMethodException
}
}
private void process(WidgetA w) {
//Do things
}
private void process(WidgetB w) {
//Do other things
}
private void process(WidgetAB w) {
//Do completely different things
}
}
abstract class Widget {
//...
}
class WidgetA extends Widget {
//...
}
class WidgetB extends Widget {
}
class WidgetAB extends WidgetA {
}
The issue here being that you have to have defined a process() method for each type of object in the things list or an exception will be thrown at run-time. The compiler will not warn you if you are missing an implementation.

Categories

Resources