Classes
Visão Geral
A linguagem 4D é compatível com o conceito de classes**. Numa linguagem de programação, a utilização de uma classe permite definir um comportamento do objecto com propriedades e funções associadas.
Uma vez que uma classe de usuário é definida, você pode instanciar objetos dessa classe em qualquer lugar do seu código. Cada objecto é uma instância da sua classe. Uma classe pode extend
outra classe e herda suas funções e propriedades (declaradas e computadas).
O modelo de classe em 4D é semelhante às classes em JavaScript, e baseado numa cadeia de protótipos.
Por exemplo, você poderia criar uma classe Pessoa
com a seguinte definição:
//Class: Person.4dm
Class constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname
Function get fullName() -> $fullName : Text
$fullName:=This.firstName+" "+This.lastName
Function sayHello() -> $welcome : Text
$welcome:="Hello "+This.fullName
Ou em um método, criar uma "Pessoa":
var $person : cs. Person //object of Person class
var $hello : Text
$person:=cs. Person.new("John";"Doe")
// $person:{firstName: "John"; lastName: "Doe" }
$hello:=$person.sayHello() //"Hello John Doe"
Gestão de classes
Definição de classe
Uma classe de usuário em 4D é definida por um arquivo method (.4dm), armazenado na pasta /Project/Sources/Classes/
específico. O nome do arquivo é o nome da classe.
Ao nomear classes, deve ter em mente as seguintes regras:
- Um nome de classe deve estar em conformidade com as regras de nomenclatura das propriedades.
- Nomes de classe diferenciam minúsculas de maiúsculas.
- Não se recomenda dar o mesmo nome a uma classe e a uma tabela de base de dados, a fim de evitar qualquer conflito.
Por exemplo, se quiser definir uma classe chamada "Polígono", precisa criar o seguinte arquivo:
Project folder
Eliminação de uma classe
Para eliminar uma classe existente, pode:
- no seu disco, remover o arquivo de classe .4dm da pasta "Classes",
- no Explorador 4D, selecione a classe e clique
ou escolha Mover para Lixo no menu contextual.
Utilização da interface 4D
Os arquivos de classe são automaticamente armazenados no local apropriado quando criados através da interface 4D, quer através do menu File, quer através do Explorer.
Menu Arquivo e barra de ferramentas
Você pode criar um novo arquivo de classe para o projeto selecionando Novo > Class... no menu File do 4D Developer ou na barra de ferramentas.
Você também pode usar o atalho Ctrl+Shift+Alt+k.
Explorador
Na página de Métodos do Explorador, as classes são agrupadas na categoria Classes.
Para criar uma nova classe, pode:
- selecione a categoria Classes e clique no botão
.
- selecione Nova Classe... no menu de ação na parte inferior da janela do Explorer, ou no menu contextual do grupo Classes.
- selecione Novo > Classe... a partir do menu contextual da página inicial do Explorador.
Suporte de código de classe
Nas várias janelas 4D (editor de código, compilador, depurador, explorador de tempo de execução), o código de classe é basicamente tratado como um método de projecto com algumas especificidades:
- No editor de código:
- uma aula não pode ser executada
- uma função de classe é um bloco de código
- Ir para a definição em um membro do objeto procura por declarações da classe Função; por exemplo, "$o.f()" encontrará "Função f".
- Procurar referências na declaração de função da classe procura a função utilizada como membro do objeto; por exemplo, "Função f" irá encontrar "$o.f()".
- No explorador e Depurador de Runtime, as funções de classe são exibidas com o formato
<ClassName>
construtor ou<ClassName>.<FunctionName>
.
Lojas de classe
As classes disponíveis são acessíveis a partir das suas class stores. Estão disponíveis duas class stores:
cs
para el class store usuario4D
para el class store integrado
cs
cs : Object
Parâmetro | Tipo | Descrição | ||
---|---|---|---|---|
classStore | Object | <- | Class store de usuário para o projeto ou componente |
O comando cs
devolve a loja de classes de utilizadores para o projecto ou componente actual. Ele retorna todas as classes de usuários definidas no projeto ou componente aberto. Por padrão, apenas as classes ORDA do projeto estão disponíveis.
Exemplo
Se quiser criar uma nova instância de um objecto de myClass
:
$instance:=cs.myClass.new()
4D
4D : Object
Parâmetro | Tipo | Descrição | ||
---|---|---|---|---|
classStore | Object | <- | Class store 4D |
O comando 4D
retorna a classe store para as classes 4D incorporadas disponíveis. Ele permite acesso a APIs específicas como CryptoKey.
Exemplo
Se quiser criar uma nova chave na classe CryptoKey
:
$key:=4D. CryptoKey.new(New object("type";"ECDSA";"curve";"prime256v1"))
Objeto da classe
Quando uma classe é definida no projeto, ela é carregada no ambiente de linguagem 4D. Uma classe é um objeto em si, da classe "Class" class. Um objecto classe tem as seguintes propriedades e função:
name
string- objeto
superclass
(nulo se não tiver) new()
função, permitindo instanciar objetos de classe- Propriedade
isShared
, true se a classe é compartilhada - Propriedade
isSingleton
, true se a classe define uma singleton. - Propriedade
me
, permitindo instanciar e acessar singletons.
Além disso, um objeto de classe pode fazer referência a um objeto construtor
(opcional).
Um objeto de classe em si é um objeto compartilhado e, portanto, pode ser acessado de diferentes processos 4D simultaneamente.
Herança
Se uma classe herda de outra classe (ou seja, a palavra-chave Class extends é usada em sua definição), a classe pai é a sua superclasse
.
Quando o 4D não encontra uma função ou uma propriedade em uma classe, ele a procura em sua superclasse
; se não for encontrada, o 4D continua procurando na superclasse da superclasse e assim por diante até não haver mais superclasse (todos os objetos herdam da superclasse "Objeto").
Palavras-chave de classe
As palavras-chave 4D específicas podem ser utilizadas nas definições de classes:
Função <Name>
para definir as funções de classe dos objetos.Construtor da classe
para inicializar novos objetos da classe.propriedade
para definir as propriedades estáticas dos objetos com um tipo.Função get <Nome>
eFunção set <Nome>
para definir propriedades calculadas dos objetos.Class extends <ClassName>
para definir a herança.
Function
Sintaxe
{shared} Function <name>({$parameterName : type; ...}){->$parameterName : type}
// code
As funções de classe são propriedades específicas da classe. Eles são objetos da classe 4D.Function. No arquivo de definição de classe, as declarações de funções usam a palavra-chave Function
seguida pelo nome da função.
Se a função for declarada em uma classe compartilhada, você pode usar a palavra-chave shared
para que a função possa ser chamada sem Use. .Finalizar estrutura
. Para obter mais informações, consulte o parágrafo Shared functions abaixo.
O nome da função deve estar em conformidade com as regras de nomenclatura de objetos.
Como propriedades e funções compartilham o mesmo espaço de nomes, usar o mesmo nome para uma propriedade e uma função da mesma classe não é permitido (um erro é lançado nesse caso).
Dica: Começar o nome da função com um caractere de sublinhado ("_") excluirá a função dos recursos de preenchimento automático no editor de código 4D. Por exemplo, se você declarar Function _myPrivateFunction
em MyClass
, ela não será proposta no editor de código quando você digitar "cs.MyClass. "`.
Imediatamente seguindo o nome da função, parameters para a função pode ser declarada com um nome e um tipo de dado atribuído, incluindo o parâmetro de retorno (opcional). Por exemplo:
Function computeArea($width : Integer; $height : Integer)->$area : Integer
Dentro de uma função de classe, o comando This
é usado como instância de objeto. Por exemplo:
Function setFullname($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname
Function getFullname()->$fullname : Text
$fullname:=This.firstName+" "+Uppercase(This.lastName)
Para uma função de classe, o comando Nome do método atual
retorna: <NomeDaClasse>.<NomeDaFunção>
, por exemplo "MinhaClasse.minhaFunção".
No código da aplicação, as funções de classe são chamadas como métodos membros das instâncias do objeto e podem receber parâmetros se existirem. São suportados os seguintes formatos:
- utilização do operador
()
. Por exemplo,myObject.methodName("olá")
- uso de um método de membro da classe "4D.Function":
Se uma função de classe não for thread-safe e for chamada por um método com o atributo "Pode ser executado num processo preemptivo":
- o compilador não gera qualquer erro (o que é diferente dos métodos normais),
- um erro é lançado por 4D apenas em tempo de execução.
Parâmetros
Os parâmetros da função são declarados utilizando o nome do parâmetro e o tipo de parâmetro, separados por dois pontos. O nome do parâmetro deve estar em conformidade com as regras de nomenclatura de propriedades. Os parâmetros (e tipos) múltiplos são separados por ponto e vírgula (;).
Function add($x; $y : Variant; $z : Integer; $xy : Object)
Se o tipo não for indicado, o parâmetro será definido como Variant
.
Valor retornado
Você declara o parâmetro de retorno (opcional) adicionando uma seta (->
) e a definição do parâmetro de retorno após a lista de parâmetro(s) de entrada, ou dois pontos (:
) e somente o tipo do parâmetro de retorno. Por exemplo:
Function add($x : Variant; $y : Integer)->$result : Integer
$result:=$x+$y
Você também pode declarar o parâmetro de retorno adicionando apenas : type
e usar a return expression
(ele também encerrará a execução da função). Por exemplo:
Function add($x : Variant; $y : Integer)->$result : Integer
Exemplo 1
property name : Text
property height; width : Integer
// Classe: Rectangle
Class constructor($width : Integer; $height : Integer)
This.name:="Rectangle"
This.height:=$height
This.width:=$width
// Definição da função
Function getArea()->$result : Integer
$result:=(This.height)*(This.width)
// In a project method
var $rect : cs. Rectangle
var $area : Real
$rect:=cs. Rectangle.new(50;100)
$area:=$rect.getArea() //5000
Exemplo 2
Este exemplo utiliza a expressão return
:
Function getRectArea($width : Integer; $height : Integer) : Integer
If ($width > 0 && $height > 0)
return $width * $height
Else
return 0
End if
Class constructor
Sintaxe
// Class: MyClass
{shared} {singleton} Class Constructor({$parameterName : type; ...})
// code
Uma função construtora de classe aceita parâmetros opcionais e pode ser usada para criar e inicializar objetos da classe de usuário.
Quando você chama a função new()
, o construtor da classe é chamado com os parâmetros opcionalmente passados para a função new()
.
Só pode haver uma função de construtor em uma classe (caso contrário um erro é retornado). Um construtor pode utilizar a palavra-chave Super
para chamar o construtor da superclasse.
É possível criar e digitar propriedades de instância dentro do construtor (ver exemplo). Em alternativa, se os valores das propriedades de instância não dependem dos parâmetros passados ao construtor, você pode defini-los usando a palavra-chave property
.
Usando a palavra-chave compartilhado
cria uma classe compartilhada, usada apenas para instanciar objetos compartilhados. Para obter mais informações, consulte o parágrafo Shared functions abaixo.
Usar a palavra-chave singleton
cria um singleton, usado para criar uma única instância. Para obter mais informações, consulte o parágrafo classes do Singleton.
Exemplo
// Class: MyClass
// Class constructor of MyClass Class Constructor ($name : Text)
This.name:=$name
// In a project method
// You can instantiate an object
var $o : cs. MyClass
$o:=cs. MyClass.new("HelloWorld")
// $o = {"name":"HelloWorld"}
propriedade
Sintaxe
property <propertyName>{; <propertyName2>;...}{ : <propertyType>}
A palavra-chave property
pode ser utilizada para declarar uma propriedade dentro de uma classe usuário. Uma propriedade de classe tem um nome e um tipo.
A declaração de propriedades de classe melhora as sugestões do editor de código, as funcionalidades de antecipação de tipos e a detecção de erros.
As propriedades são declaradas para novos objetos quando você chama a função new()
, no entanto elas não são automaticamente adicionadas aos objetos (elas são adicionadas apenas quando lhes é atribuído um valor).
Uma propriedade é adicionada automaticamente ao objeto quando é inicializado na linha de declaração.
O nome do parâmetro deve estar em conformidade com as regras de nomenclatura de propriedades.
Como propriedades e funções compartilham o mesmo espaço de nomes, usar o mesmo nome para uma propriedade e uma função da mesma classe não é permitido (um erro é lançado nesse caso).
O tipo de propriedade pode ser um dos seguintes tipos suportados:
Sintaxe | Conteúdos |
---|---|
Text | Valor texto |
Date | Valor data |
Time | Valor Hora |
Boolean | Valor booleano |
Integer | Valor inteiro longo |
Real | Valor real |
Pointer | Valor ponteiro |
Picture | Valor imagem |
Blob | Valor BLOB |
Collection | Valor colecção |
Variant | Valor variant |
Object | Object with default class (4D.Object) |
4D.<className> | Objecto do nome da classe 4D |
cs.<className> | Objeto do nome da classe usuário |
cs.<namespace>.<className> | Objeto do nome da classe do componente <namespace> |
Se você omitir o tipo na linha de declaração, a propriedade é criada como uma variante.
A palavra-chave property
só pode ser utilizada em métodos de classe e fora de qualquer bloco Function
ou Class Constructor
.
Inicializando a propriedade na linha de declaração
Ao declarar uma propriedade, você tem a flexibilidade de especificar seu tipo de dados e fornecer seu valor em uma única instrução. A sintaxe suportada é:
property <propertyName> { : <propertyType>} := <Propertyvalue>
Ao usar essa sintaxe, você não pode declarar várias propriedades na linha de declaração.
Você pode omitir o tipo na linha da declaração, caso em que o tipo será inferido quando possível. Por exemplo:
// Class: MyClass
property name : Text := "Smith"
property age : Integer := 42
property birthDate := !1988-09-29! //data é inferida
property fuzzy //variant
Quando você inicializa uma propriedade em sua linha de declaração, ela é adicionada ao objeto da classe após sua instanciação com a função new()
, mas antes que o construtor seja chamado.
Se uma classe estende outra classe, as propriedades da classe pai são instanciadas antes das propriedades da classe filho.
Se você inicializar uma propriedade em sua linha de declaração com um objeto ou uma coleção em uma classe compartilhada, o valor é automaticamente transformado em um valor compartilhado:
// em uma classe compartilhada
propriedade minhaColecao := ["algo"]
// minhaColecao será uma coleção compartilhada
// equivalente a:
minhaColecao := Nova coleção compartilhada("algo")
Exemplo
// Class: MyClass
property name : Text
property age : Integer
property color : Text := "Blue"
Num método:
var $o : cs.MyClass
$o:=cs.MyClass.new() //$o:{"color" : "Blue"}
$o.name:="John" //$o:{"color" : "Blue"; "name" : "John"}
$o.age:="Smith" //error com a sintaxe checada
Função get
e Function set
Sintaxe
{shared} Function get <name>()->$result : type
// código
{shared} Function set <name>($parameterName : type)
// código
Função obter
e Função definir
são acessores que definem propriedades computadas na classe. Uma propriedade calculada é uma propriedade nomeada com um tipo de dados que oculta um cálculo. Quando um valor de propriedade computado é acessado, 4D substitui o código do acessor correspondente:
- quando a propriedade é lida, a
função obter
é executada, - quando a propriedade é escrita, o
conjunto de função
é executado.
Se a propriedade não for acedida, o código nunca é executado.
As propriedades computadas são concebidas para tratar dados que não precisam de ser guardados na memória. São geralmente baseados em propriedades persistentes. Por exemplo, se um objeto de classe contiver como propriedade persistente o preço bruto e a taxa de IVA, o preço líquido poderia ser tratado por uma propriedade calculada.
No arquivo de definição de classe, as declarações de propriedade computadas usam as palavras-chave Função
(a getter) e Function set
(as setter), seguido pelo nome da propriedade. O nome deve estar em conformidade com as regras de nomenclatura de propriedades.
A função get
devolve um valor do tipo de propriedade e A função set
recebe um parâmetro do tipo de propriedade. Ambos os argumentos devem estar em conformidade com os [parâmetros de função] padrão (#parâmetros).
Quando ambas as funções são definidas, a propriedade computada é read-write. Se apenas uma Function get
for definida, a propriedade computada será somente leitura. Neste caso, é devolvido um erro se o código tentar modificar a propriedade. Se apenas um Function set
estiver definido, 4D devolve undefined quando a propriedade é lida.
Se as funções forem declaradas em uma classe compartilhada, você pode usar a palavra-chave shared
com elas para que elas possam ser chamadas sem Use. .Finalizar estrutura
. Para obter mais informações, consulte o parágrafo de [Funções Compartilhadas](#funções compartilhadas) abaixo.
O tipo da propriedade calculada é definido pela declaração de tipo $return
do getter. Pode ser de qualquer tipo de propriedade válida.
A atribuição de undefined a uma propriedade de objeto apaga seu valor enquanto preserva seu tipo. Para fazer isso, a
Function get
é chamada primeiro para recuperar o tipo de valor, em seguida, aFunction set
é chamada com um valor vazio desse tipo.
Exemplo 1
//Class: Person.4dm
property firstName; lastName : Text
Class constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname
Function get fullName() -> $fullName : Text
$fullName:=This.firstName+" "+This.lastName
Function set fullName( $fullName : Text )
$p:=Position(" "; $fullName)
This.firstName:=Substring($fullName; 1; $p-1)
This.lastName:=Substring($fullName; $p+1)
//num método projecto
$fullName:=$person.fullName // A função get fullName() é chamada
$person.fullName:="John Smith" // A função set fullName() é chamada
Exemplo 2
Function get fullAddress()->$result : Object
$result:=New object
$result.fullName:=This.fullName
$result.address:=This.address
$result.zipCode:=This.zipCode
$result.city:=This.city
$result.state:=This.state
$result.country:=This.country
Class extends <ClassName>
Sintaxe
// Classe: ChildClass
Classe estende <ParentClass>
A palavra-chave Class extends
é usada na declaração de classe para criar uma classe de usuário que é filho de outra classe de usuário. A classe filha herda todas as funções da classe mãe.
A extensão de classe deve respeitar as seguintes regras:
- Uma classe de usuário não pode estender uma classe embutida (exceto 4D.Object e classes ORDA que são estendidas por padrão para classes de usuário).
- Uma classe de usuário não pode estender uma classe de usuário de outro projeto ou componente.
- Uma classe usuário não se pode estender a si própria.
- Não é possível estender classes de forma circular (ou seja, "a" estende "b" que estende "a").
- Não é possível definir uma classe de usuário compartilhado estendida de uma classe de usuário não compartilhada.
A violação de uma regra deste tipo não é detectada pelo editor de código ou pelo interpretador, apenas o compilador e check syntax
emitirão um erro neste caso.
Uma classe estendida pode chamar o construtor da sua classe pai usando o comando Super
.
Exemplo
Este exemplo cria uma classe chamada Square
a partir de uma classe chamada Polygon
.
//Class: Square
/path: Classes/Square. dm
Classe estende o construtor Polygon
Classe ($side : Integer)
// Ele chama o construtor da classe pai com comprimentos
// fornecido para a largura e a altura
Super($side;$side)
// Em classes derivadas, Super deve ser chamado antes de você
// pode usar 'Isso'
Isso. ame:="Quadrado"
Função getArea() -> $area : Integer
$area:=This.height*This.width
Super
Super( ...param : any )
Super : Object
Parâmetro | Tipo | Descrição | |
---|---|---|---|
param | any | -> | Parâmetro(s) a passar para o construtor pai |
Resultados | Object | <- | Pai do objecto |
A palavra-chave Super
permite chamadas à superclasse
, ou seja, a classe pai.
Super
tem dois objectivos diferentes:
- Dentro de um código de construtor,
Super
é um comando que permite chamar o construtor da superclasse. Quando usado em um construtor, o comandoSuper
aparece sozinho e deve ser usado antes que a palavra-chaveThis
seja usada.
- Se todos os construtores de classe na árvore de herança não forem correctamente chamados, é gerado o erro -10748. É o programador 4D que se certifica de que as chamadas são válidas.
- Se o comando
This
for chamado em um objeto cujas superclasses não foram construídas, o erro -10743 será gerado. - Se o
Super
é chamado fora do escopo do objeto, ou em um objeto cujo construtor de superclasse já foi chamado, erro -10746 é gerado.
// dentro do construtor myClass
var $text1; $text2 : Text
Super($text1) //chama o construtor da superclasse com um parâmetro de texto
This.param:=$text2 // usa o segundo parâmetro
- Dentro de uma função de membro da classe,
Super
designa o protótipo da superclasse e permite chamar uma função da hierarquia da superclasse.
Super.doSomething(42) //chamada a função "doSomething"
//declarada em superclasses
Exemplo 1
Este exemplo ilustra o uso do Super
em um construtor de classe. O comando é chamado para evitar duplicar as partes do construtor que são comuns entre as classes Rectangle
e Square
.
// Classe: Retângulo
Class constructor($width : Integer; $height : Integer)
Isso. ame:="Retângulo"
Isso.height:=$height
Isso. idth:=$width
Função diz: Name()
ALERT("Oi, eu sou um "+This.name+". )
// Definição de função
função getArea()
var $0 : Integer
$0:=(This.height)*(This.width)
//Class: Square
Class extends Rectangle
Classe construtor ($side : Integer)
// Ele chama o construtor da classe pai com comprimentos
// fornecido para a largura e altura
Super($side;$side)
// Em classes derivadas, Super deve ser chamado antes de você
// pode usar 'Isso'
Isso. ame:="Quadrado"
função getArea()
C_LONGINT($0)
$0:=Isso.height*Este.width
Exemplo 2
Este exemplo ilustra a utilização de Super
em um método de membro da classe. Você criou a classe Rectangle
com uma função:
//Classe: Rectângulo
Function nbSides()
var $0 : Text
$0:="I have 4 sides"
Você também criou a classe Square
com uma função que chama a função da superclasse:
//Classe: Quadrado
Class extends Rectangle
Function description()
var $0 : Text
$0:=Super.nbSides()+" que são todos iguais"
Depois pode escrever num método projecto:
Parâmetros
This
This : Object
Parâmetro | Tipo | Descrição | |
---|---|---|---|
Resultados | Object | <- | Objecto actual |
A palavra-chave Isso
retorna uma referência ao objeto processado .
Na maioria dos casos, o valor de Isso
é determinado pela forma como uma função é chamada. Não pode ser definido por atribuição durante a execução e pode ser diferente de cada vez que a função é chamada.
Quando um formula é chamado como método de membro de um objeto, seu Isso
está configurado para o objeto no qual o método é chamado. Por exemplo:
$o:=New object("prop";42;"f";Formula(This.prop))
$val:=$o.f() //42
Quando uma função construtor de classe é usada (com a new()
), sua This
estará ligada ao novo objeto que está sendo construído.
//Classe: ob
Construtor de Classe
// Crie propriedades em This conforme
// desejado atribuindo a elas
This.a:=42
// num método 4D
$o:=cs.ob.new()
$val:=$o.a //42
Quando chamar o construtor da superclasse num construtor utilizando a palavra-chave Super , esteja atento que This não deve ser chamado antes do construtor da superclasse, caso contrário é gerado um erro. Veja este exemplo.
Em qualquer caso, This
refere-se ao objeto em que o método foi chamado, como se o método estivesse no objeto.
//Class: ob Function f()
$0:=This.a+This.b
Depois pode escrever num método projecto:
$o:=cs.ob.new()
$o.a:=5
$o.b:=3
$val:=$o.f() //8
Neste exemplo, o objeto atribuído à variável $o não tem sua própria propriedade f, herda-o de sua classe. Uma vez que f é chamado como um método de $o, o seu This
refere-se a $o.