unit conta; 
  
interface 
  
uses 
  SmartCL.System; 
  
type 
  TWEstadoConta = class; 
  
  TWConta = class 
    private 
      _Estado : TWEstadoConta; 
      _NroConta : Integer; 
      _NomeCorrentista : String; 
  
      procedure VerificaStatus; 
  
    public 
  
      Constructor Create(ANomeCorrentista: String); 
      Destructor Destroy;override; 
  
      { Operações } 
      procedure Depositar (AValor : Float); 
      procedure Sacar     (AValor : Float); 
      procedure AplicarRendimento; 
  
      function ObtemSaldo : Float; 
      function ObtemNroConta : Integer; 
  
      function ObtemEstado : TWEstadoConta; 
  end; 
  
  TWEstadoConta = class 
    protected 
      _Saldo : Float; 
      _PorcRendim : Float; 
      _LimInf, _LimSup : Float; 
      _Conta : TWConta; 
  
      Constructor Create (AConta : TWConta);virtual; 
      procedure CopyFrom (AContaOrg : TWEstadoConta);virtual; 
  
    public 
      Destructor Destroy;override; 
  
      procedure Depositar (AValor : Float);virtual;abstract; 
      procedure Sacar     (AValor : Float);virtual;abstract; 
      procedure AplicarRendimento;virtual;abstract; 
  end; 
  
  TWContaComum = class(TWEstadoConta) 
    protected 
      _TaxaServico : Float; 
  
      Constructor Create (AConta : TWConta);override; 
    public 
      procedure Depositar (AValor : Float);override; 
      procedure Sacar     (AValor : Float);override; 
      procedure AplicarRendimento;override; 
  end; 
  
  TWContaDiferenciada = class(TWContaComum) 
    protected 
      _TaxaJuros : Float; 
      Constructor Create (AConta : TWConta);override; 
  
    public 
      procedure Depositar (AValor : Float);override; 
      procedure Sacar     (AValor : Float);override; 
      procedure AplicarRendimento;override; 
  end; 
  
  TWContaOuro = class(TWEstadoConta) 
    protected 
      Constructor Create (AConta : TWConta);override; 
    public 
      procedure Depositar (AValor : Float);override; 
      procedure Sacar     (AValor : Float);override; 
      procedure AplicarRendimento;override; 
  end; 
  
implementation 
  
{ 
  C l a s s e    T W C o n t a 
} 
  
Constructor TWConta.Create(ANomeCorrentista: String); 
begin 
  _Estado := Nil; 
  _NroConta := Trunc (Now * 100.0); 
  _NomeCorrentista := ANomeCorrentista; 
  VerificaStatus (); 
end; 
  
Destructor TWConta.Destroy; 
begin 
//  FreeAndNil (_Estado); 
  inherited; 
end; 
  
function TWConta.ObtemNroConta : Integer; 
begin 
  Result := _NroConta; 
end; 
  
function TWConta.ObtemEstado : TWEstadoConta; 
begin 
  Result := _Estado; 
end; 
  
procedure TWConta.VerificaStatus; 
var lNovoEstado : TWEstadoConta; 
begin 
  { A conta é do tipo Comum por padrão } 
  if (_Estado = Nil) then begin 
    _Estado := TWContaComum.Create(Self); 
    Exit; 
  end; 
  
  { Testa as variações de estado } 
  lNovoEstado := Nil; 
  if (_Estado._Saldo < _Estado._LimInf) then 
  begin 
    { Rebaixa de COMUM para DIFERENCIADA } 
    if (_Estado is TWContaComum) then begin 
    //  WriteLn('C - D'); 
      lNovoEstado := TWContaDiferenciada.Create (Self); 
      end; 
    { Rebaixa de OURO para COMUM } 
    if (_Estado is TWContaOuro) then begin 
    //  WriteLn('o - c'); 
      lNovoEstado := TWContaComum.Create (Self); 
      end; 
  end; 
  
  if (_Estado._Saldo > _Estado._LimSup) then 
  begin 
    { Eleva de COMUM para OURO } 
    if (_Estado is TWContaComum) then begin 
  //    WriteLn('c -> O'); 
      lNovoEstado := TWContaOuro.Create (Self); 
      end; 
    { Rebaixa de OURO para COMUM } 
    if (_Estado is TWContaOuro) then begin 
    //  WriteLn('O -> c'); 
      lNovoEstado := TWContaComum.Create (Self); 
      end; 
    { Eleva de Diferenciada para Comum } 
    if (_Estado is TWContaDiferenciada) then begin 
    //  WriteLn('D -> c'); 
      lNovoEstado := TWContaComum.Create (Self); 
      end; 
  
  end; 
  
  { Efetiva a troca de estado } 
  if (lNovoEstado <> Nil) then 
  begin 
    { Copia dados relevantes do estado atual } 
    lNovoEstado.CopyFrom(_Estado); 
  
    { Libera estado atual } 
    _Estado.Free; 
  
    { Considera novo Estado } 
    _Estado := lNovoEstado; 
  end; 
end; 
  
function TWConta.ObtemSaldo : Float; 
begin 
  Result := _Estado._Saldo; 
end; 
  
procedure TWConta.Depositar (AValor : Float); 
begin 
  _Estado.Depositar(Avalor); 
  VerificaStatus (); 
end; 
  
procedure TWConta.Sacar (AValor : Float); 
begin 
  _Estado.Sacar (AValor); 
  VerificaStatus (); 
end; 
  
procedure TWConta.AplicarRendimento; 
begin 
  _Estado.AplicarRendimento (); 
  VerificaStatus (); 
end; 
  
{ 
  C l a s s e    T W E s t a d o C o n t a 
} 
  
Constructor TWEstadoConta.Create (AConta : TWConta); 
begin 
  _Conta := AConta; 
  _Saldo := 0.0; 
  _PorcRendim := 0.0; 
  { Valores de saldo que delimitam um estado } 
  _LimInf := 0.0; 
  _LimSup := 0.0; 
end; 
  
Destructor TWEstadoConta.Destroy; 
begin 
  _Conta := Nil; 
  inherited; 
end; 
  
procedure TWEstadoConta.CopyFrom (AContaOrg : TWEstadoConta); 
begin 
  { Copia apenas as informações relevantes para a conta. As informações 
    que são específicas do estado, como a taxa de rendimento, devem permanacer 
    conforme configuradas no próprio estado. } 
  _Saldo := AContaOrg._Saldo; 
  _Conta := AContaOrg._Conta; 
end; 
  
{ 
  C l a s s e    T W C o n t a C o m u m 
} 
  
Constructor TWContaComum.Create (AConta : TWConta); 
begin 
//  inherited; 
  
  _PorcRendim := 1.0; { Rendimento padrão : 1%} 
  _TaxaServico := 5.00; { Saques são cobrados } 
  { Valores de saldo que delimitam um estado } 
  _LimInf := 100.00; 
  _LimSup := 999.99; 
end; 
  
procedure TWContaComum.Depositar (AValor : Float); 
begin 
  _Saldo := _Saldo + AValor; 
end; 
  
procedure TWContaComum.Sacar (AValor : Float); 
var lValorReal : Float; 
begin 
  lValorReal := AValor + _TaxaServico; 
  _Saldo := _Saldo - lValorReal; 
end; 
  
procedure TWContaComum.AplicarRendimento; 
begin 
  _Saldo := _Saldo + (_Saldo * _PorcRendim) / 100.0; 
end; 
  
{ 
  C l a s s e    T W C o n t a D i f e r e n c i a d a 
} 
  
Constructor TWContaDiferenciada.Create (AConta : TWConta); 
begin 
//  inherited; 
  
  _PorcRendim  :=  0.0; { Sem rendimento } 
  _TaxaJuros   := 1.00; { Taxa de juros sobre saques qdo a conta fica sem saldo } 
  _TaxaServico := 10.00; { Saques são cobrados } 
  
  { Valores de saldo que delimitam um estado } 
  _LimInf := -100.00; 
  _LimSup :=   99.99; 
end; 
  
procedure TWContaDiferenciada.Depositar (AValor : Float); 
begin 
  _Saldo := _Saldo + AValor; 
end; 
  
procedure TWContaDiferenciada.Sacar (AValor : Float); 
var lJuros, lValorReal : Float; 
begin 
  lValorReal := AValor + _TaxaServico; 
  if (_Saldo - lValorReal) < _LimInf then 
    raise Exception.Create('Saque não pode ser efetivado. Conta sem saldo.'); 
  
  lJuros := 0.0; 
  if (_Saldo - lValorReal) < 0.0 then 
    lJuros := (lValorReal - _Saldo) * _TaxaJuros / 100.0; 
  
  _Saldo := _Saldo - lValorReal - lJuros; 
end; 
  
procedure TWContaDiferenciada.AplicarRendimento; 
begin 
 { Esse tipo de conta não dá rendimentos } 
end; 
  
{ 
  C l a s s e    T W C o n t a O u r o 
} 
  
Constructor TWContaOuro.Create (AConta : TWConta); 
begin 
//  inherited; 
  _PorcRendim := 2.00; { Rendimento Ouro : 2% } 
  { Valores de saldo que delimitam um estado } 
  _LimInf :=  1000.00; 
  _LimSup := 99999.99; 
end; 
  
procedure TWContaOuro.Depositar (AValor : Float); 
begin 
  _Saldo := _Saldo + AValor; 
end; 
  
procedure TWContaOuro.Sacar (AValor : Float); 
begin 
  _Saldo := _Saldo - AValor; 
end; 
  
procedure TWContaOuro.AplicarRendimento; 
begin 
  _Saldo := _Saldo + (_Saldo * _PorcRendim) / 100.0; 
end; 
  
end. 
 |