1

I'm looking for an improved solution to the following problem. I have an object, which is passed to a factory; the factory will inspect the object type, create another type, which it populates with data from the incoming object, and returns the new one.

...

public MyAbstractClass create(MyObject a) {

    if (a instanceof A) {
        A obj = (A) a;
        return new MyAbstractClass_1 (obj.getField(), factoryField);
    } 
    else if (a instanceof B) {
        B obj = (B) a;
        return new  MyAbstractClass_2 (obj.getSomething(), obj.getSomethingElse(), factoryField);
    } 

}

Instances of the return type are treated generically afterwords. Going forward I need to support more types and if possible I'd like to avoid an instanceof solution. How can I improve this?

2 Answers 2

3

Can you add the create method to MyObject instead? That way you won't need instance of anymore because each instance of MyObject knows how to 'create'. You won't have a factory anymore though :(

It would look something like (assuming MyObject is an interface. if it's a class, then just extend instead):

interface MyObject {
  ...
  public MyAbstractClass create(MyObject a);
  ...
}

public class A implements MyObject {
  ...
  public MyAbstractClass create(MyObject a) {
    return new MyAbstractClass_1 (obj.getField(), factoryField);
  }
  ...
}

public class B implements MyObject {
  ...
  public MyAbstractClass create(MyObject a) {
    return new MyAbstractClass_2 (
      obj.getSomething(),
      obj.getSomethingElse(),
      factoryField);
  }
  ...
}
Sign up to request clarification or add additional context in comments.

Comments

1

The bodies of your if statements should be virtual or abstract members on MyObject.

abstract class MyObject {
   public abstract MyAbstractClass create();
}

class A extends MyObject {
   @Override
   public MyAbstractClass create(Object factoryField) {
      return new MyAbstractClass_1 (this.getField(), factoryField);
   }
}

class B extends MyObject {
   @Override
   public MyAbstractClass create(Object factoryField) {
      return new  MyAbstractClass_2 (this.getSomething(), this.getSomethingElse(), factoryField);
   }
}

Generally, when you see yourself checking the type of an object to do something different depending on the concrete type, that likely means that you should be using polymorphism and the code should be going into the concrete types themselves.

Updated that the MyObject data should be coming from the current instance and not passed as a parameter, as you pointed out. Only issue is that I'm not sure where you'd put factoryField now. You could pass it as a parameter as above, and since these are virtual members you could still have a factory as well:

class SomeFactory {
   private Object factoryField;

   public SomeFactory(Object factoryField) {
      this.factoryField = factoryField;
   }

   public MyAbstractClass create(MyObject a) {
      return a.create(factoryField);
   }
}

3 Comments

What's the reason for the create method to take any argument? The implementation has what it needs to create the object - except for factoryField.
@user1491636 you're right, that info should be coming from the instance now
You're updated solution is one I was thinking of... not sure if it's really a factory anymore though:)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.