1

I need to modify the data members of a class, but since there are a lot of use cases, I would like to put the modifier methods in separate classes to not make the main class too large.

So I'm thinking of making the data members protected, and using derived classes as interfaces to modify the data members for each different use case.

Is this a common solution to my problem? Is this a good way of solving it, or is there something better?

3
  • What other types of methods are in the class making it "too large"?
    – user949300
    Commented Oct 3, 2017 at 15:11
  • @user949300 Methods for all use cases. Not counting the use cases that will modify the data members, the class will only have getters and a constructor.
    – devil0150
    Commented Oct 3, 2017 at 18:13
  • Sounds like your concern is that you have "a lot of use cases", bordering on too many for this class. This is a possible indication that your class is trying to do too much and violates the Single Responsibility Principle. Unfortunately, the SRP is ill-defined, very poorly understood, and discussion of it usually leads to more heat than light. Without knowing more of your project, it's hard to say, but you should consider breaking your use-cases into smaller groups, and seeing if that leads to a new class design with more, but smaller, classes.
    – user949300
    Commented Oct 4, 2017 at 19:11

1 Answer 1

2

I need to modify the data members of a class, but since there are a lot of use cases, I would like to put the modifier methods in separate classes to not make the main class too large.

I think it's a good idea to extract the modification logic outside the class that defines the members. It sounds like your data members are a model and the modification logic is probably business logic. Please correct me if I'm wrong.

So I'm thinking of making the data members protected, and using derived classes as interfaces to modify the data members for each different use case. Is this a common solution to my problem? Is this a good way of solving it?

I've never seen something like this before, and it doesn't sound like good design to me. Here are the reasons:

is there something better?

I would take a different approach. I would make the model class immutable:

class Foo {
    private final Integer a;
    private final String b;

    public Foo(Integer a, String b) {
        this.a = a;
        this.b = b;
    }

    public Integer getA() { return a; }
    public String getB() { return b; }
}

Now that I have a model, I want to transform it. I can define a model transformation:

interface FooTransformation {
    Foo transform(Foo foo);
}

You can now express all your use cases in terms of FooTransformation implementations like so:

class UseCase1 implements FooTransformation {
    public Foo transform(Foo foo) {
        return new Foo(foo.getA() + 5, foo.getB() + "world");
    }
}

This design has some good things:

  • Immutable model
  • Easy to unit test use cases
2
  • 1
    Currently this is only the beginning of the project, but I think performance will be important in later stages. Instantiating a new object for every modification seems a little heavy.
    – devil0150
    Commented Oct 2, 2017 at 22:35
  • 1
    Would be a nice addition to mention how mutating a supertype's protected state via the subtype would violate the history constraint of LSP: "Because subtypes may introduce methods that are not present in the supertype, the introduction of these methods may allow state changes in the subtype that are not permissible in the supertype. The history constraint prohibits this."
    – Dioxin
    Commented Oct 5, 2017 at 23:45

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.