Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Dorian Neto

Abstração

Recommended Posts

Boa noite pessoas :)

 

Em meu sistema, possuo uma pasta chamada core onde ficam os arquivos base para funcionamento do sistema. Possuo uma classe dentro desta pasta chamada de Application onde nela eu informo as informações da aplicação(versão, nome do autor, etc) e extendo uma classe abstrata chamada Route onde eu crio o sistema de rotas do sistema.

 

Minha dúvida é exatamente com relação a essa última classe(Route). Seria interessante deixá-la como uma classe abstrata mesmo ? Cheguei a conclusão de deixá-la abstrata a partida do seguinte princípio: Rotas em um sistema é algo abstrato, agora rotas gerenciadas pela aplicação são concretas.

 

Estou certo nessa forma de pensar ou estou viajando muito ? Ou talvez bastante ? kkkkkkkk Esse é meu primeiro sistema onde estou aplicando a fundo meus estudos de POO, MVC e Design Patterns.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A minha classe de roteamento é abstrata e, através de uma interface posso ter tantos tipos de roteamento quantos eu quiser.

 

Tá certo que por enquanto só tenho um baseado em SQLite, mas isso não vem ao caso :yay:

Compartilhar este post


Link para o post
Compartilhar em outros sites

@HivePass

 

Seu post foi bastante esclarecedor :) Tinhas as mesmas dúvidas que você com relação a routers e me identifiquei bastante com a forma como você se expressa(também sou bastante metódico e refatoro meu código direto! kkkkk).

 

Minha ideia com relação aos routers era fazer exatamente o que você fez de começo, criar métodos mágicos onde eles iriam identificar os parâmetros passados via get e instanciaria o controller correspondente. Pensei em deixá-lo como abstrato justamente pelo fato de que eu tenho uma classe da aplicação, e pensei em jogar a responsabilidade de fazer criar os routers nessa classe... Mas depois de ter escrito isso achei meio sem lógica essa minha idéia...

 

Com pouco conhecimento que tenho de laravel e depois de ter lido as dicas do @EnricoPereira irei esquecer a forma como iria criar os routers e irei criar routers manuais :P

 

--------------------------

Fiquei bastante empolgado com o assunto e acabei achando esse projeto, que por sinal é brasileiro: http://imasters.com.br/linguagens/php/respect-um-microframework-de-respeito/

Ele resolve meu problema das rotas :DD

 

link do projeto: http://respect.li/

--------------------------

 

 

@BrunoAugusto

 

através de uma interface posso ter tantos tipos de roteamento quantos eu quiser.

 

Não entendi muito bem o motivo pelo qual você tem interfaces para routers.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Só não confunda nomenclatura. Classe abstrata != abstração.

 

Classe abstrata é uma classe que serve de base para as outras.

Abstração é a capacidade de um módulo/software de executar uma tarefa sem precisar depender de algo específico (ex. posso inserir uma query sem depender do MySQL).

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Enrico Pereira

O que entendo de abstração é isso:

 

A palavra cachorro é uma abstração do objeto cachorro, correto ? Quando falo a palavra cachorro, logo vem na mente de todos uma ou várias raças de cachorros.

 

Se eu transferir esse conceito para a POO, eu teria uma classe abstrata chamada cachorro onde a mesma teria método e propriedade gerais de um cachorro onde classes de raças de cachorro herdariam esta classe.

 

 

Abstração é a capacidade de um módulo/software de executar uma tarefa sem precisar depender de algo específico

Só não entendi uma coisa nessa sua afirmativa. Como eu classifico que um módulo possui abstração ? Quanto menos ele depender de algo específico, mais abstração ele tem ? Acho que não estou conseguindo expressar corretamente minha dúvida, mas é pq realmente ficou muito confuso pra mim :S

 

 

@Vinicius Rangel

 

As interfaces servem então neste caso apenas para mostrar para outros programadores que aqueles métodos são necessários para funcionamento daquele objeto e consequentemente do sistema. Correto ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

As interfaces servem então neste caso apenas para mostrar para outros programadores que aqueles métodos são necessários para funcionamento daquele objeto e consequentemente do sistema. Correto ?

Não apenas mas ajuda.

 

aproveitando o gancho do cachorro...

 

Uma interface de cachorro seria um animal.

 

então você define nessa interface animal os métodos andar, deitar, correr.

 

agora imagina que você tem um objeto que define corridas de animais mais especificamente de cachorros.

 

se você dizer lá que cachorros apostam corridas se um dia você precisar que um cavalo corra também você vai começar criar vários if's no seu código para identificar um ou outro.

 

já com a interface você passa para o objeto que seta as corridas que você precisa de um animal e então o cachorro extende a interface animal ganhando um contrato dizendo vc obrigatoriamente precisa andar, deitar e correr.

 

então esse contrato deixa o seu código flexiviel a mudanças.

 

Acho que é só isso.. auhahuahuhauhua

Compartilhar este post


Link para o post
Compartilhar em outros sites

Isso é um exemplo duma abstração (eu não consegui fazer o esquema de spoiler p/ o post não ficar enorme, sorry):

<?php

// Apenas exceptions, nada demais aqui...
namespace Config\Exceptions;

use Exception;

class FileNotFound extends Exception
{
    public function __construct($file)
    {
        parent::__construct(sprintf(
            'File not found: "%s".', $file
        ));
    }
}

class NoReader extends Exception
{
    public function __construct($extension)
    {
        parent::__construct(sprintf(
            'There\'s no reader defined able to read "%s." files.', $extension
        ));
    }
}

// As classes que podem ler diferentes tipos de arquivos de configuração..
namespace Config\Readers;

use Config\File;

interface ConfigReader
{
    public function read(File $file);
    public function getExtension();
}

class JsonConfigReader implements ConfigReader
{
    public function read(File $file)
    {
        return json_decode($file->getContents(), true);
    }

    public function getExtension()
    {
        return 'json';
    }
}

class PhpConfigReader implements ConfigReader
{
    public function read(File $file)
    {
        return require $file->getFile();
    }
    public function getExtension()
    {
        return 'php';
    }
}

// Uma classe para tratamento básico de arquivos..
namespace Config;

use Config\Exceptions\FileNotFound;

class File
{
    private $file;

    public function __construct($file)
    {
        if (! file_exists($file)) {
            throw new FileNotFound($file);
        }

        $this->file = $file;
    }

    public function getContents()
    {
        return file_get_contents($this->file);
    }

    public function getExtension()
    {
        return pathinfo($this->file, PATHINFO_EXTENSION);
    }

    public function getFile()
    {
        return $this->file;
    }
}

// Classe de configuração, que utiliza algum dos leitores para ler a configuração.
namespace Config;

use Config\Readers\ConfigReader;
use Config\Exceptions\NoReader;

class Config
{
    private $readers = [];
    private $configs = [];

    public function addReader(ConfigReader $reader)
    {
        $this->readers[$reader->getExtension()] = $reader;
    }

    public function read($file)
    {
        $fileObject = new File($file);

        if (! isset($this->readers[$fileObject->getExtension()])) {
            throw new NoReader($extension);
        }

        $reader = $this->readers[$fileObject->getExtension()];
        $content = $reader->read($fileObject);

        $this->configs = array_merge_recursive($this->configs, $content);
    }

    public function getConfigs()
    {
        return $this->configs;
    }
}

 

E esse código é abstrato porque conseguimos ler arquivos sem depender especificamente de qual leitor, veja:

use Config\Readers;
use Config\Config;

$config = new Config();
$config->addReader(new Readers\JsonConfigReader());
$config->addReader(new Readers\PhpConfigReader());
$config->read('database.json');
$config->read('secrets.php');

var_dump($config->getConfigs()); // O array com todas as configs

 

Foi possível usar diferentes tipos de arquivos para configurar e você pode criar vários diferentes leitores de configuração, pois o código é abstrato, ou seja, não depende especificamente de leitores de configuração, mas sim de um contrato abstrato.

 

E note que nem foram usadas classes abstratas.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Um exemplo bem simples:

 

 

 

interface FazAlgo {
     public function getResultado();
}

class ExecutaAlgo {
     public function __construct(FazAlgo $oQueVaiSerFeito){
                $oQueVaiSerFeito->getResultado();
     }
}

class MostraAlgo implements FazAlgo{

      private $s;

      public function __construct($string){
               $this->s = $string;
      }

       public function getResultado(){
             echo($this->s);
       }
}


class SomaDoisValores implements FazAlgo{

     private $r;

     public function __construct($numero1,$numero2){
              $this->r = $numero1 + $numero2;
     }

     public function getResultado(){
             echo('soma: '.$this->r);
     } 
}



$mostra = new MostraAlgo('ola, isto esta sendo mostrado...');
$executa = new ExecutaAlgo($mostra);

echo '
';

$soma = new SomaDoisValores(2,5);
$executa2 = new ExecutaAlgo($soma);

?>

bem simples, ta certo que na hora o caldo engrossa...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Aqui vamos nós...

 

@Enrico Pereira

Classe abstrata é uma classe que serve de base para as outras.

 

Justamente por isso que eu perguntei porque ele iria utilizar uma classe abstrata para o sistema de roteamento.

 

Eu estudei muito de ontem para hoje códigos diversos de roteamento e percebi que cada um intepreta o sistema de rotas de uma forma diferente, por isso, como eu creio que é um assunto extenso, eu vou escrever em um tópico distinto sobre o que eu acho sobre as rotas, o que eu percebi e qual a visão de outros sistemas sobre rotas.

 

Segue o tópico: http://forum.imasters.com.br/topic/504797-sistema-de-rotas-routing/

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Enrico Pereira

 

Perfeita sua explicação :) Agora sim minha ficha caiu :DD

 

@Vinicius Rangel

 

Interessante sua explicação :)

 

 

Obrigado a todos que me ajudaram !

Abraços.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Justamente por isso que eu perguntei porque ele iria utilizar uma classe abstrata para o sistema de roteamento.

 

O "Cara do X-Tudo" ( :lol: ) ainda tá confundindo abstração de uma classe com o conceito de abstração.

 

Como foi dito pelo Enrico no seu outro tópico, um Router apenas mapeia URI à um callback ou, complementando aqui, instruções para que o Dispatcher possa transformar em um "tipo" callable válido.

 

Como eu nunca usei o Respect\Router como Enrico parece usar que atrela um callback manualmente definido à cada nova URI a ser mapeada. Pra mim isso não faz muito sentido mas tenho certeza que é só uma certa... "deficiência" na documentação e demonstrar um caso de uso real.

 

Mas assumido o segundo cenário em que o Router mapeia uma URI e prepara informações para serem usadas por Dispatcher, uma dessas informações seria a classe do Controller e o método nessa classe a ser invocado.

 

Como a confiança dos seus objetos vêm através das Interfaces, definir os accessors nelas é obrigatório, então:

<?php
 
interface Router {
 
    public function find( Request $request );
 
    public function getController();
 
    public function getAction();
}

Veja que também temos um método Router::find() que é como o Dispatcher disparará o processo de análise e localização com base na URI atualmente em curso.

 

E, dessa forma, o Dispatcher que usa um objeto polimórfico Router tem a garantia de pelo menos esses três métodos existirem:

<?php
 
class Dispatcher {
 
    public function __construct( Router $router ) {
 
        $this -> dispatch( $router -> find( new Request ) );
    }
 
    private function dispatch( stdClass $data ) {
 
        // Do something with found informations
    }
}

Acredito que para o propósito não importe o que é a classe Request. :thumbsup:

 

Nesse cenário bem simples, abstrair a classe Router apenas evit que repitamos a declaração dos métodos Router::getController() e Router::getAction(), afinal, Router::find() pode (e tecnicamente deve) variar.

 

Confesso que eu já tive muitos problemas com esse tipo de Syntatic Sugar, então passei a assumir quase que em 100% dos casos que uma classe abstrata só deve existir se possuir algum método de implementação mutável que não seja público.

 

No caso de um Router, um bom exemplo é verificação de integridade.

 

Um Router baseado em arrays não tem nenhum tipo de requerimento. Mas e um como o meu atual, baseado em SQLite? Ou um baseado em Memcache, talvez?

 

Sem abstração teríamos algo assim:

<?php
 
class MemcacheRouter implements Router {
 
    private $controller;
    private $action;

    public function __construct() {
 
        if( ! class_exists( 'Memcache' ) ) {
 
            throw new Exception( 'Memcache Extension not loaded' );
        }
    }

    public function find( Request $request ) {

    }

    public function getController() {
        return $this -> controller;
    }

    public function getAction() {
        return $this -> action;
    }
}

E num baseado em SQLite algo similar, apenas mudando o class_exists() por extension_loaded().

 

Repetimos a implementação de dois métodos, disparamos uma Exception no construtor do objeto e forçamos o uso de propriedades privadas que, não é errado, mas é bom evitar.

 

Poderíamos mover a verificação para outro método e invocá-lo no construtor. Em cada construtor, de cada implementação... Péra! Dá pra refatorar isso aí!

<?php
 
abstract class AbstractRouter implements Router {
 
 
    protected $controller;
 
    protected $action;
 
    public function __construct() {
 
        $this -> checkRequirements();
    }
 
    // Interface Methods Implementation
 
    public function getController() {
        return $this -> controller;
    }
 
    public function getAction() {
        return $this -> action;
    }
 
    // Abstract Method Definition
 
    abstract protected function checkRequirements();
}

E nossos Routers que agora derivam de AbstractRouter, terão apenas de implementar os métodos Router:find() que é sua lógica própria e o método abstrato:

<?php

class MemcacheRouter extends AbstractRouter {

    public function find( Request $request ) {

        // Do something
    }

    protected function checkRequirements() {

        if( ! class_exists( 'Memcache' ) ) {

            throw new Exception( 'Memcache Extension not loaded' );
        }
    }
}

Ficou mais limpo, elegante e faz mais sentido.

 

Agora, antes que pessoal do TDD venha me dizer que esse código não é muito testável, que viola OCP e tal, eu não manjo de TDD e não entendi uma vírgula do artigo que o João Batista escreveu (achei que tivesse, mas não).

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.