Packaging in Kotlin

Asked

Viewed 141 times

0

I am starting my studies in Kotlin and am trying to solve the following problem:

Create a class to represent a person, with private attributes of name, date of birth and height. Create the necessary public methods for sets and gets and also a method to print all a person’s data. Create a method to calculate the age of the person.

By making attributes private, I couldn’t access them anymore. How can I use "getters" and "setters" to access attributes?

My code:

fun main() {
    val dadosJoao = Dados()
    dadosJoao.nome = "João"
    dadosJoao.altura = 1.83
    dadosJoao.nascimento = 1948
    println(dadosJoao.nascimento)
    println(dadosJoao.altura)
    println(dadosJoao.calculaIdade())

}

class Dados {
    var nome = ""
    var idade = 0
    var altura = 0.0
    var nascimento = 0

    fun calculaIdade(idade: Int)  {
        idade = 2021 - nascimento
        return this.idade
    }
}

1 answer

2


If you try to access these attributes of your object dadosJoao (actually the right is to call them fields) from outside the class as you did, in that function main() who does not belong to the class Dados, these attributes cannot be accessed because they will not be visible. They are only visible to code (functions) that is being declared within your class Dados, as was the case with its last function calculaIdade(). That’s what it means to be private.

Note that this latter function, if public, you can call from outside the class from an object in that class, for example from the object dadosJoao making dadosJoao.calculaIdade(), so if you program this function to return the value of a private field, this value will be accessible by whoever calls this function outside the class and gets its return.

If a function belongs to a class (which leads us to call this function "method"), you can only call it if you have a reference (variable) to an object that was created based on that class, as is the case with its variable dadosJoao.

The intention is not to expose these fields directly to the outside of the class, but in a more controlled manner through public methods, say, "gatekeepers".

Thus it is possible to control by code that the date of birth of an object is defined only once and is not changed more often, for example. If it goes public this will not be possible because at any time a date of birth of the person to whom it belongs may be changed, which would be undesirable (by the way, note by the data in question that you are modeling (designing) a class Pessoa, that class name is more appropriate in your case than Dados. This is because this Person class will not only have data, but also behaviors (functions/methods that interact with this data).

If you declare a public or at least private function getNome() within its class that returns as a result the value of a field nome that is private in the class (because it has been declared within the class this function has access to the fields of that class even if they are private, it is a matter of scope and visibility), this function will be what many call getter. The field nome will remain inaccessible directly by anyone outside the class calling meuObjeto.nome, but will be accessible in an indirect way calling in its place meuObjeto.getNome(). I just don’t know exactly how to do it in Kotlin syntax.

To understand better it is necessary to have the notion of what are encapsulation and information Hiding (concealment of information) in object orientation.

First let’s remember that a class is a "formwork" that you program with the intention of defining what objects to be created based on this class will have in terms of state (variables) and behavior (logic) during code execution. There for each object that is instantiated (created) this state will vary individually, both from how they were initialized and based on the interaction between different objects of different classes in their application. Roughly speaking, in class-based object orientation.

Basically, in objects you should have the principle of isolating what is "on the inside" from what is "on the outside" of an object building a kind of logical barrier in the class that defines it using concepts such as access modifiers (making it private, public, etc.) applied to fields (which is the name given to variables that have been programmed to belong to the object, as opposed to local or global variables) and methods (which is the name given to these programmed "functions" within a class and which end up belonging to that class, or rather to its objects), as well as practicing a certain way of programming classes.

This allows you to isolate what is inside the object (implementation details, data structures that don’t matter outside what they are, specific algorithms) from what is seen outside the object, which is more stable. This stability is very desirable. It becomes possible to make changes and improvements to the internal parts of the object that will not necessarily impact the public interface (the public methods) provided by the object, which are the "services" or the high-level utility that this object offers to its users. The goal is always to try to minimize this impact and expose an interface as stable as possible.

Getter is the name given to a public method, or at least not-private, which exposes (returns) some information from within the object. As this method belongs to the class you are programming, it has access to private fields of this class and can even return them on the return of the function, effectively "publishing" these fields to those who call this method from the outside.

The staff usually make the association that a getter called for example getNome() should always bring the variable nome which is private within the object, and for many a getter is just that, but this is not necessarily true, since a "naked" getter invalidates this logical barrier (which in some cases, as objects that simply serve to carry data, is not a problem, but can be in objects that are part of the so-called domain model, which implement business rules for example).

Same thing the setters, that are public or private methods that change something within the object and the staff sees much as setNome(novoNome), to change a private field nome, but that shouldn’t necessarily be true.

The concept of object means putting together some state and the behaviors associated with that state, that of putting together those two things that are related and giving them a name is what is called encapsulation. Withholding information is this separation that I described between the public interface and the implementation/internal state details, which stem from isolating these two sides logically (many people confuse this with encapsulation).

In your case when your name fields, etc. were public, the withholding of information was not taking place. When they were deprived this happened. If you create getters and setters for them it may or may not fail to occur, especially if you do not validate data in Setter, or expose fields that should not be modified, such as data_de_nascimento, providing a Setter to them, or exposing a mutable internal state (as a reference to another object stored internally) that is subject to change directly from the outside, rather than an immutable copy of that information. Already one getIdade() whose return is calculated from the date of birth, preserves the concealment of information (you are not exposing the date of birth) and demonstrates the concept of encapsulation.

What you will get in a public interface depends on the services that are interesting an object to provide. A class Pedido for example can be implemented containing a list of products internally (private) and it may be interesting that this request offers a public method getTotal(), which does not necessarily mean that within exists a field total private, and rather that he can calculate this total by going through the list of products and adding the prices from one to one.

A Setter can even directly change a private field, but it can (and should) validate the new value being provided, because it acts as a doorman between the external and the internal side, which is protected, including receiving invalid data (which would leave the object in an invalid state).

An object of the class Pessoa can expose his age by a getIdade() calculated from a field data_de_nascimento. Also, it may for some reason not be interesting to expose the date of birth directly, so avoid creating a getDataDeNascimento(), for example. Much less would it make sense to have a Setter to modify the date of birth, which by definition should be fixed and immutable.

The same general principle applies to constructors, who must validate all arguments passed to them in order to validly initialize the internal state of the object.

I do not know if I answered your question because I do not know the specific syntax of Kotlin for all this, but I hope I helped with these important concepts and given a basis to find the answer in the syntax.

Browser other questions tagged

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