2

This question is in the context of an Android application written in Java.

I have this class which performs a specific action and returns the result of such action with a callback implemented in the activity where it was called. This class depends on the current activity reference. This is not a singleton because this class can be called from different activities.

One obvious solution could be something like this:

public class MyClass {

    private final Activity mActivity;
    private Callback mCallback;

    public MyClass(Activity activity, Callback callback) {
        mActivity = activity;
        mCallback = callback;
    }

    public void initialize() {
        // do something...
        mCallback.onFinished();
    }

    public interface Callback {
        void onFinished();
    }

}

public class MainActivity implements MyClass.Callback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new MyClass(this, this).initialize();
    }

    @Override
    public void onFinished() {
        // do something...
    }

}

This works and it's fine, I guess. But I really don't like the new MyClass(this, this).initialize(); line. That new just doesn't feel right.

This is when I came up with a slightly different solution and with a small variation on the parameters:

public class MyClass {

    private final Activity mActivity;

    private MyClass(Activity activity) {
        mActivity = activity;
    }

    public static MyClass with(Activity activity) {
        return new MyClass(activity);
    }

    public void initialize(Callback callback) {
        // do something...
        callback.onFinished();
    }

    public interface Callback {
        void onFinished();
    }

}

public class MainActivity implements MyClass.Callback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyClass.with(this).initialize(this);
    }

    @Override
    public void onFinished() {
        // do something...
    }

}

Does the exact something, but instead of explicitly creating an instance with the new keyword, it is created implicitly with the static with() method.

Maybe this is just a matter of preference but IMO this feels more natural than using the new keyword. Perhaps the with and initialize names are not the best ones, but what do you guys think of this?

Do you have a third alternative?

9
  • 1
    In my opinion, neither in intrinsically better than the other. Just use what you (and the others on the project) feel most comfortable with. Commented Aug 9, 2016 at 11:04
  • Thanks @BartvanIngenSchenau. But if you had to do something similar to this yourself, how would you do it?
    – rfgamaral
    Commented Aug 9, 2016 at 11:09
  • @RicardoAmaral from the post it seems you have a preference, why not just go with that?
    – user82096
    Commented Aug 9, 2016 at 11:11
  • @dan1111 I do. But I'm also interested in other's opinions for a possible different/better alternative, or perhaps my approach is flawed in some way?
    – rfgamaral
    Commented Aug 9, 2016 at 12:14
  • 1
    You fix that with the static factory method you re-invented: public static MyClass with(Activity activity) { return new MyClass(activity); }, though note that all you really did was push the new somewhere else. Commented Aug 9, 2016 at 15:59

1 Answer 1

1

IIRC Josh Bloch wrote in "Effective Java" that the second approach is preferred but that because of the expectations of developers constructors should be used in simple situations or something to that effect.

There is a fundamental difference here that I think is worth pointing out. Calls to a constructor are inherently coupled to the type in question. If you create a factory method, the actual object created can be any sub-type of the class. You may never need that but it does offer flexibility that is hard to replicate in a raw constructor.

Additionally, code in a constructor is subject to restrictions that don't apply to the static method. For example, you may need to call out to something else to determine what to pass into a super constructor or perhaps which version of the super constructor to call. These kinds of things are difficult to impossible inside the constructor but are simple in a factory method.

On a side note, I generally try to avoid init or initialize type methods. In my experience, the separating initialization from construction is asking for problems. Sometimes it is unavoidable but using factory methods or related approaches that keep the object in a narrow scope until it is fully initialized can completely mitigate these problems.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.