Propriedades

É uma boa prática de orientação à objetos ocultar detalhes da implementação para os úsuarios de suas classes(Princípio de ocultação de informações(em inglês)), então você pode depois mudar os internos sem quebrar a API pública. Uma pratica é tornar os campos privados e prover métodos de acessos para pegar e determinar os seus valores(getters e setters).

Se você é um programador Java você vai provavelmente pensar em algo assim:

class Pessoa : Object {
    private int idade = 32;

    public int get_idade() {
        return this.idade;
    }

    public void set_idade(int idade) {
        this.idade = idade;
    }
}

Isso funciona, mas Vala pode fazer melhor. O problema é que esses métodos são incomodos de se trabalhar. Vamos supor que você quer incrementar a idade da pessoa em um ano:

var alice = new Pessoa();
alice.set_idade(alice.get_idade() + 1);

É aqui que as propriedades entram em ação:

class Pessoa : Object {
    private int _idade = 32;  // prefixo sublinhado para evitar um cruzamento de nome com a propriedade

    /* Propriedade */
    public int idade {
        get { return _idade; }
        set { _idade = value; }
    }
}

Essa sintaxe deve ser familiar a programadores C#. A propriedade tem um get e um set para inserir e retornar seu valor. value é uma palavra chave que representa o novo valor que deve ser atribuído a propriedade.

Agora você pode acessar a propriedade como se ela fosse um campo público. Mas por trás das cenas o código é executado pelos setters e getters.

var alice = new Pessoa();
alice.idade = alice.idade + 1;  // ou até mais curto:
alice.idade++;

Se você só faz a implementação padrão como mostrada acima você pode escrever as propriedades de maneira mais curta:

class Pessoa : Object {
    /* Propriedade com um getter e setter e valor padrão */
    public int idade { get; set; default = 32; }
}

Com propriedades você pode mudar o trabalho interno das classes sem mudar sua API pública. Por exemplo:

static int ano_atual = 2525;

class Pessoa : Object {
    private int ano_de_nascimento = 2493;

    public int idade {
        get { return ano_atual - ano_de_nascimento; }
        set { ano_de_nascimento = ano_atual - value; }
    }
}

Agora a idade é calculada na hora pelo ano de nascimento. Note que você pode fazer mais que acessar uma simples variavel ou atribuição com os blocos get e set. Você poderia fazer um acesso à banco de dados, logs, atualizações de cache, etc.

Se você quer fazer uma propriedade somente-leitura para os usuarios da classe você deve fazer o setter privado:

    public int idade { get; private set; default = 32; }

Ou alternativamente, você pode deixar o bloco set de fora:

class Pessoa : Object {
    private int _idade = 32;

    public int idade {
        get { return _idade; }
    }
}

Propriedades podem não apenas ter um nome mas também uma curta descrição(chamado nick) e uma descrição longa(chamada blurb). Você pode anotar esses com um atributo especial:

    [Description(nick = "idade em anos", blurb = "Essa é a idade da pessoa em anos")]
    public int age { get; set; default = 32; }

Propriedades e suas descrições adicionais podem ser requeridas em tempo de execução. Alguns programas como a ferramenta gráfica de design de interfaces de usuario Glade faz uso dessa informação. Dessa forma Glade pode mostrar descrições legíveis por humanos para propriedades dos widgets GTK+.

Toda instancia de uma classe derivada da GLib.Object tem um sinal chamado notify. Esse sinal é emitido toda vez que uma propriedade de seus objetos muda. Então você pode conectar a esse sinal se estiver interessado nas notificações de mudanças em geral:

obj.notify.connect((s, p) => {
    stdout.printf("A propriedade '%s' mudou!\n", p.nome);
});

s é a origem do sinal (obj nesse exemplo), p é a informação da propriedade do tipo ParamSpac para a propriedade mudada. Se você só está interessado nas notificações de mudança de uma única propriedade você pode usar essa sintaxe:

alice.notify["idade"].connect((s, p) => {
    stdout.printf("idade mudou\n");
});

Note que nesse caso você precisa usar a representação verbal do nome da propriedade aonde sublinhas são substituidas por traços: nome_da_propriedade se torna nome-da-propriedade nessa representação, que é a convenção de nomeação de propriedades nos GObjects.

A notificação de mudanças pode ser desabilitada com um atributo CCode imediatamente antes da declaração da propriedade:

public class MyObject : Object {
    [CCode(notify = false)]
    // sinal notify NÃO é emitido nas mudanças da propriedade
    public int sem_notificacao { get; set; }
    // sinal notify é emitido nas mudanças da propriedade
    public int com_notificacao { get; set; }
}

Há outro tipo de propriedades chamado propriedades de construção(construct properties) que são descritos depois na seção sobre construção no estilo gobject.

Nota: no caso de sua propriedade ser do tipo struct, para receber o valor da propriedade com Object.get(), você tem que declarar sua variável como no exemplo abaixo

struct Cor
{
    public uint32 argb;

    public Cor() { argb = 0x12345678; }
}

class Forma: GLib.Object
{
    public Cor c { get; set; default = Cor(); }
}

int main()
{
    Cor? c = null;
    Forma f = new Forma();
    f.get("c", out c);
}

Dessa forma, c é uma referência invés de uma instancia de Cor no stack. O que você passou ao s.get() é "Cor **" invés de "Cor *".

results matching ""

    No results matching ""