Is this a common practice in object orientation?

Asked

Viewed 1,580 times

12

In object orientation, one way to ensure encapsulation is to maintain the attributes of the private classes and modify their state via methods. In addition, to ensure the integrity of objects, it is common to require that data essential to the existence of the object be passed in the constructor.

In classes with few attributes this works well. It turns out that in classes with a very large number of attributes, it starts to get a little strange. An example of this is this class PessoaJuridica (that I recognize not to be very good):

public class PessoaJuridica
{
    public string NomeFantasia { get; set; }

    public string RazaoSocial { get; set; }

    public string Endereco { get; set; }

    public string Bairro { get; set; }

    public string Cidade { get; set; }

    public string Estado { get; set; }

    public int CEP { get; set; }

    public int Telefone1 { get; set; }

    public int Telefone2 { get; set; }

    public int Fax { get; set; }

    public int CNPJ { get; set; }

    public int InscricaoEstadual { get; set; }

    public int InscricaoMunicipal { get; set; }

    public DateTime DataConstituicao { get; set; }

    public DateTime DataCadastro { get; set; }

    public string Observacoes { get; set; }
}

The class has several attributes. Going through all this in the constructor is unviable, and even choosing a subset to pass would still be bad. Also building a method for each attribute would not have much advantage over what is already there. So I thought of the following improvement:

I looked in the class at some things that make sense grouped together. For example:

  • Address, Neighborhood, City, State, Zip Code collectively form the Company Address
  • Phone1, Phone2 and Fax are types of phones
  • CNPJ, Registracaoestadual, Inscricaomunicipal and Dataconstituticao form a company documentation

That’s why I coded a struct Endereco with properties "Street, Number, Neighborhood, City, State, ZIP code", a struct Telefone with properties "DDD, Numero, Tipotelefone" being "Tipotelefone" an Enum that can be "Fixed" or "Fax". I finally coded a struct DocumentacaoEmpresa with attributes "Razaosocial, CNPJ, Inscribed State, Inscribed Community and Date Constitution". With this I stayed with the class

public class PessoaJuridica
{
    public string NomeFantasia { get; private set; }

    public Endereco Endereco { get; private set; }

    public IList<Telefone> Telefones { get; private set; }

    public DocumentacaoEmpresa Documentacao { get; private set; }

    public string Observacoes { get; set; }
}

And then it becomes easier to use methods and the builder to deal with this class. What I did was I took a class with multiple attributes, grouped those attributes into concepts that make sense and encoded those concepts. In addition, you now have a phone list to obey the Open/Closed principle.

What I’d like to know is: is this a common practice in object orientation? The construction of these structs was not made because they were domain concepts, but rather to improve the writing of a class. Is there any Pattern design, or anything like that?

I know you don’t need a Pattern design for something to be valid, but I wanted to know if it’s common and if there’s more information about it to see if it’s a good idea to do this sort of thing.

4 answers

15


Solution to the problem

First I’ll give you the simple solution to your problem of initializing a large amount of properties:

var pessoa = new PessoaJuridica {
    NomeFantasia = "abc",
    RazaoSocial = "abc",
    Endereco = "rua abc",
    Bairro = "abc",
    Cidade = "abc",
    Estado = "sp",
    CEP = "12345678",
    Telefone1 = "12345678",
    Telefone2 = "12345678",
    Fax = "12345678",
    CNPJ = "11111111000111",
    InscricaoEstadual = "11111111111",
    InscricaoMunicipal = "1111111",
    DataConstituicao = new DateTime(2000, 4, 15),
    DataCadastro = new DateTime(DateTime.Today),
    Observacoes = "abc"
}

I put in the Github for future reference.

This is called Object initializer.

I moved some to string because it makes no sense that they are integers. Just because a given has only digits does not mean that it is a number. Zip code, phone, CNPJ are identifiers and not numbers.

Note that what you have done does not facilitate the creation of the instance. On the contrary, you will still have to pass all the data, but now in a slightly more extensive way. I’m not saying I shouldn’t do it to organize, but it doesn’t simplify the creation of the object.

Why does the builder exist?

Not always a constructor is needed, at least in C#. There are languages that turn out well without a.

Constructors must give atomicity in the creation of the object. That is, either create the object in a valid state or not create. If you need to validate the data and if some validation fails the object should not be created, then a constructor helps a lot. The same is true if some "calculation" is required with the initial parameters before creating the object.

So we can conclude that it only makes sense to pass to a constructor data that must exist on a valid object or that must be processed before being inserted into the object.

The object initiator helps with this atomicity, but it does not completely replace the constructor. In C# 6 it is even better with the property initializers where it is possible to make a public string NomeFantasia { get; set; } = "" (only example, of course this initialization is not desirable). If the validation of the data are individual this works well, but if the validation is interdependent there only constructor will solve elegantly.

What replaces the constructor then? At first nothing. If you need what it offers only it can provide. What is possible is to create a utility class to create a temporary object and then throw this object into the definitive class but rarely does this make any sense. I made a question about this.

Separating some properties into auxiliary classes doesn’t help at all in this. On the contrary, it is possible - although I do not think this is the case of the example shown - to break the atomicity of the creation of the object by doing so. Even if it doesn’t break, it will possibly complicate the creation of the main object by having to check things in two places. Not to mention the creation of intermediate objects that would be discarded if the creation of the main object is not completed.

More information about constructor.

Proper modeling

If the problem was the amount of constructor parameters and you decided to encapsulate some properties in other classes and make a composition just to solve this problem, then I can say that this is not common. You are organizing your data to meet a language engine need. This is definitely not common, at least in expressive languages such as C#.

So I have my doubts whether it is easier to use methods and constructor to deal with the class as stated.

It was created because you think it makes sense to organize the data like this, ok, it’s common to do this. But it doesn’t mean that this is always or almost always done. It depends on the case, it depends on your problem, the requirements set, the understanding of how you need to model the data.

Address

Is there a reason to organize the address in a class? Do you have any advantage in having this data separate? Can you need this data separately from the legal entity? In simple models in general do not need, in more complex models can really have advantages in having separate and well defined. Who is more purist, will say it should always be done.

Documentation

The same can be said for documentation, but the conclusion may be different. I think there is less reason to have them encapsulated. I can see the address as an autonomous entity, but I think that each document is already an autonomous entity and I can’t see much sense in grouping them apart from meeting the need for the mechanism, which has already been said is not ideal. But the real need of the domain worked can say otherwise. This is why I don’t like good practices (the big problem is that most people don’t know how to use them properly), they ignore the real problem.

Phones

I’m not sure I understand, but I don’t think creating a phone list has anything to do with the Open/Close principle. Anyway the reason to create a list is the fact that the number of phones is undetermined. Note that your refactoring does not produce the same result. In the first one you have any two phones and a fax. In the second one you can have from zero to infinity phones - although you can restrict this with algorithms - and you may not know what each one represents, all of them are generic - of course in this class, you may have an extra property that determines what type of phone is.

Completion

I cannot say for sure whether it is common practice, it is not always easy to say this with propriety except in very obvious cases. But it seems to me to be the wrong solution. You yourself gave the reason when you say you are not doing it because of the domain.

I am not a purist and if I really need it, if I have a very good reason to do something because of the mechanism, I will do it, but whenever I can I will avoid it, it just won’t be at any cost.

The Pattern design what you are doing is composition. But if you think about it all the properties make composition. It does not need to be a complex property to compose the class. When it comes to preferring composition, it is the most obvious and natural way to assemble a type that is composition. This is the intuitive way we do and we don’t even realize we’re doing it in every kind being created.

In that reply I’ve said patterns are everywhere.

  • 1

    Thank you for the reply @bigown. What I said about Open/Closed was in the following sense: at the time of coding there are two telephones and a fax. Later it may be necessary to add another telephone, or a second fax. As it was it would be necessary to modify the code, in the new way it is possible to add the functionality without modifying: just add a new number to the list. That’s the idea of Open/Closed isn’t it? Being able to add things without modifying what already exists. Maybe I misunderstood Open/Closed.

  • 1

    I don’t follow these principles. I even follow by coincidence. I happen to do something that fits some of them, but I don’t pursue them. There are situations that simply need to change the class, it would be ridiculous to keep raising a daughter class every time it needs a change. So I have my doubts whether the principle applies in this case. Anyway I think it talks more about behavior. Although technically properties are behaviors, deep down they are just proxies for the state. So I don’t know if it’s right or not. But me I wouldn’t worry about it. I wouldn’t apply it

  • 1

    The phone is not the only problem. You mean you can’t place a new property? Because if O/C is that, the systems are extremely inflexible. Your concern with the phone makes sense, as I show in the answer, but I think it is independent of the O/C problem that is a widespread problem. Another thing that I was thinking that the O/C problem only actually appears when there is inheritance. Classes that have daughters should be frozen anyway. I understand that any change can generate undesirable effects but it is impracticable to modify certain classes.

  • 1

    One of the reasons to avoid inheritance is to avoid these principles that even valid. They try to solve the problem that object orientation possesses. They show you the path you must follow to avoid what is known that will bring trouble. So some think that the default of classes should be sealed, which cannot be inherited. The moment you raise daughters of the class you have responsibilities and commitments. As in real life, this is not always desirable. You lose the freedom to do whatever you want with the class under pain of breaking the daughters.

  • 1

    Not fully related but it shows the problem of these principles and "Good practices": http://sklivvz.com/posts/i-dont-love-the-single-responsibility-principle. In general these things are almost arbitrary. That’s why I prefer more general things that give a general idea of what to do. When it gets very specific, it pleases people more because they tell them that they don’t know what to do, even though this is stupid. They are created to sell books, consultancies, etc. It is Snake oil. Their intention and foundation are good but the result is disastrous.

2

I use the Java language, but it is very similar C#.

What you could do is create an abstract class called Third (abstract classes cannot be instantiated) and create a class called Juridical, not abstract that extends from Third (you can instantiate the Juridical class). And for Phones, as I saw above, you can make a class only for phones, without having two attributes Phone1 and Phone2.

In Java it would look like this, I believe it is not very different from C#:

public abstract class Terceiro{

}

public class Juridica extends Terceiro {

}

Attributes such as RG, Name, Telephone would be placed in the abstract class Third and attributes such as CNPJ in the Juridical class.

Other classes like Physics could extend from Third and this could have an attribute called CPF.

This would be a great object orientation practice, I hope it helps.

  • In C# you change the extends for :, and adds the other implementations with ,, following the order of NomeClasse : ClasseBase, Implement1, Implement2, etc :D

1

0

An object-oriented application is a network of objects that collaborate with each other for objectives.

The responsibilities that each object must fulfill are distributed more or less equally through these objects so that they are not accumulated in a single object and difficult to maintain.

If you’re going to do it methodically, what’s missing in your case is domain modeling. It is an activity of Object-Oriented Analysis and Design.

In domain modeling you create a conceptual domain model (conceptual Domain model), which is distinct from the design model.

A common way to find domain entity candidates is to extract nouns and noun expressions from a requirement document. Then these candidates are refined or eventually discarded. Also the relationships between the entities are determined.

Then in the above case you would identify that there is a Personal entity and an Address entity with address attributes, among others. In mapping the conceptual model to the design you would create specific classes for these entities.

When you go straight to implementation often do not notice this modeling and the fields tend to accumulate in some entities.

I will not detail the process first because I do not master it and second because it would be very extensive. It is a subject to be researched and studied.

Browser other questions tagged

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