0

Tl;dr: In terms of the "high cohesion and low coupling" principle, how do I best deal with many simple objects that need to access the strings.xml resource in order to correctly parse an output?

I'm setting up an app in android studio that handles accounts and stores payments to those accounts. I have set up a class for payments and accounts respectively and until now tried to keep them as simple as possible, so they don't have to store any references to other classes. However, since this is an android app, I want to make use of the formatting options provided by the strings.xml resource file.

My question is, is there a way to keep the classes as simple as possible(i.e. not have them deal with the main activity to get the strings.xml resource), while also preserving the simplicity of payment.getTimeString() call?

And if not, in terms of high cohesion and low coupling, would it be smarter to give all those elements a reference to the main activity, so they can access the strings.xml resource? Or would it be smarter to create a function in a handler class, that transforms the output of the payment- or account objects, which would mean that, when switching activities for example, I not only have to reference the object I want the new activity to work with, but also the handler that transforms the output? Or is there a different solution entirely that I'm not thinking about?

Example A:
Payment Class:

public class Payment implements Serializable {
    private Calendar time;
    private Activity mainActivity;
    [...]

    public Payment(Calendar time, Activity mainActivity, ...) {
        this.time = time;
        this.mainActivity = mainActivity;
        [...]
    }

    [...]

    public String getTimeString() {
        DateFormat dateFormat = new SimpleDateFormat(mainActivity.getResources().getString(R.string.dateFormat));
        return dateFormat.format(time.getTime());
    }
}

Example B:
Payment Class:

public class Payment implements Serializable {
    private Calendar time;
    [...]

    public Payment(Calendar time, ...) {
        this.time = time;
        [...]
    }

    [...]

    public Calendar getTime() {
        return time;
    }
}

AccountHandler:

public class AccountHandler implements Serializable {
    private Activity activity;
    [...]

    public AccountHandler(MainActivity activity) {
        this.activity = activity;
    }

    public String parseTime(Calendar time) {
        DateFormat dateFormat = new SimpleDateFormat(mainActivity.getResources().getString(R.string.dateFormat));
        return dateFormat.format(time.getTime());
    }
}
  • These are not equivalent. In the former case, Payment is being bound to both time and activity; whereas in the latter case, AccountHandler is bound to the activity and the Payment is not used at all! That they are not equivalent is ok, but there's insufficient context to tell which is ~better for your situation. I would probably try to move toward an interface (implemented by activity) that directly offers the proper format and encapsulates any further manipulation. – Erik Eidt Aug 6 at 0:15
  • My thinking was that that for example A, an activity wanting to get the date stored in Payment as a String, could do so by simply calling Payment.getTimeString(), whereas for example B, an activity would have to call AccountHandler.parseTime(Payment.getTime()), which would mean that I have to pass that activity not only the Payment object it's going to work with, but also a reference to AccountHandler. – UmBottesWillen Aug 6 at 0:19
  • Ok, well, still not enough context for me to say, but, in general it is better to keep usage of consuming clients simple rather than keeping classes simple. We want our users (fellow programmers, often ourselves) to fall into the "pit of success". – Erik Eidt Aug 6 at 0:34
  • 2
    Consider ease of use in automated tests as a motivator (in both Examples); There's a need to mock extra dependencies and provide extra stubs for methods in both cases, which adds more complexity to the usage of your classes in a test. getTimeString/parseTime might be a candidate for refactoring out separately (maybe TimeFormatter, or a pure function which takes Calendar/Activity as arguments), since it doesn't really seem to make sense that classes about Payments or Accounts should need to know about formatting a Date/Time - that sounds like a separate responsibility to me. – Ben Cottrell Aug 6 at 6:09
  • 2
    I don't think the two goals you pose in your question title are mutually exclusive. – Robert Harvey Aug 6 at 18:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.