How to avoid the use of setters in such cases?

Asked

Viewed 271 times

10

In object orientation it is recommended to avoid the use of setters. The usual justification for this is that the logic that modifies the state of an object must be encapsulated in the object. Therefore, the ideal is the object to expose behaviors, and these behaviors have as a side effect their state modification.

The traditional example is a class representing a bank account. Instead of using a Setter to modify the balance, the balance is modified as a side effect of transactions such as transfers. It would be something like

public class ContaBancaria
{
    public Saldo { get; private set; }

    public bool Transfere(decimal valor, ContaBancaria conta)
    {
        // Logica de transferencia
    }
}

It turns out that in some cases it is easy to identify state modification as a side effect of an object’s behavior. In the case of the account, the balance is modified when banking operations are carried out. In the case of a product that has its quantity controlled in stock, the quantity would be modified in buying and selling processes, etc.

The problem is that there are situations that it is really complicated to identify the state modification in this way.

Some examples: a class that models a client, a class that models a user, a class that models a company.

In general these classes are part of the domain. They are concepts of problem space, are terms of ubiquitous language, and are necessary for domain operations. More than that, in general these classes have several properties.

For example: a customer has a name, has a CPF, has an associated email address, has a phone, an address, etc.

And that confuses me. Because it is necessary to expose features to modify this state: change the name, the CPF, the email, the phone, the address, etc.

The problem is: what behavior is responsible for these changes? I think a lot and it doesn’t. When trying to give a name to the method that changes the name for example, I have no idea what it would be.

If I go this way, I’ll end up creating a method ModificaNome, but this is totally equivalent to a Setter.

In these cases, where we cannot identify in principle a behavior responsible for changing the state of a set of properties, how we managed to avoid the use of setters and obtain a good object-oriented design?

  • 4

    The question starts from a wrong premise. You just don’t have to avoid using setters. Use setters whenever you need to.

3 answers

11


The good design object-oriented solves problems in the best possible way. When it is used to meet meaningless rules, it is not good design. If someone told you that you need to do this, you better review your influences (which is your right to choose them, because the one who has to bear the consequences is yourself).

As a side note maybe this is due to an obsession with a methodology that says something ideological.

Do the Setter and ready. There is something that is the modification of the state pure and simple, has nothing to invent. Or nor do the Setter if it really isn’t necessary. And is not always. This seems heresy to some, but it is a valid solution when you know what you are doing. The links show a little more when avoid. Even if you don’t want to go for it because who knows, maybe one day, maybe, you’ll need it and "the D.O.D.told me you have to," so use it.

I don’t know if the DDD says to avoid the Setter, If you do, it’s just one more reason to put methodology aside. Medicine helps you, drugs consume you. I even agree that if it’s natural to avoid it, do it, but don’t let artificialisms determine your path.

There is a methodology that is a collection of good practices that, as this question shows, bring more problems than solutions. The only good practice is doing the right thing in every situation. Either accept this generic fact to guide you, or analyze the specific case to get an answer of what you need. Trying to find concrete answers patterns in abstract cases doesn’t usually work, because it generates such good practice.

So in the more or less concrete case presented in the question, what is the problem of having a property Nome of Cliente not to do something special? If you cannot answer this question definitively and simply, you are looking for a horn on a horse’s head. On the other hand, if you can change the data in another way, it can be interesting, it can give more semantics.

6

Great maturity in your interpretation. What you’re realizing is that, an oblique entity has its vision modified by whoever is looking at it. Taking the example of a Person:

  • The government sees you as RG, CPF, Estado Civil, etc;
  • Your parents see you as Father’s Eyes, Mother’s Smile, Voice Tone, etc;
  • The doctor sees you as Sex, Weight, Height, Cholesterol, etc;
  • The postman sees you as Name, Zip Code, Number, etc;

That means, the same entity changes to face context.

In software architecture, this Pattern is called Bounded Context or Bounded Contexts.

This posture meets this "nuisance" that you are feeling. Your complete solution can, and should, have micro-modules/services - totally isolated, including. In the person registration module, you have the entity Person with name, date of birth, telephones, finally, information relevant to the context of registration of persons.

And in another module, banking, you have the entity Comptroller, where it has agency, account, signature image, etc. In this module, its entity has setters to manipulate bank data, but none to manipulate people’s records. And vice versa.

In conclusion, look at Delimited Contexts that will meet this need you’re already feeling, and make all the sense in software development responsibly.

6

Leonardo, your question is good and a specific part has caught my attention:

The problem is: what behavior is responsible for these changes?

Note that sometimes the alteration of a simple information is a great behavior in itself. Who will say whether it is or is not it will be yourself who is the expert in the business.

Since you cited CPF as an example, what would be the existing process in your business to exchange CPF?

  • It is necessary to check if there is already any other client using this CPF?
  • This CPF is required not to be on the bad payroll?
  • Need to ensure that the number matches the name that was informed?

Understand that if at least one validation is required we can say that change a social security number is something dangerous and involves complexity, becoming an expected behavior of your system. To deal with this complexity we remove the settler to encapsulate the change. We want to ensure that this CPF exchange will not generate an invalid state. Note that there is no ideology here. Only good practices.

Of all the examples you gave of attributes (name, CPF, address, email, phone) most likely, in any slightly more complex system, would be considered Valueobjects due to immutability.

Meanwhile...

If changing the CPF doesn’t mean anything in your project is just a simple value assignment, so you don’t have complexity involved. If you don’t have complexity involved, you don’t need tools/processes/techniques to deal with such complexity. Therefore, DDD (or anything else to handle complexity) would be Overengineering

Browser other questions tagged

You are not signed in. Login or sign up in order to post.