Enrico Pereira 299 Denunciar post Postado Agosto 8, 2013 Bem, você está preso em conceitos e com dificuldades em compreender a real utilização disso. O problema é que é dito que a intenção da orientação a objetos é aproximar o código ao mundo real, mas na verdade não é. O objetivo da OOP é possibilitar uma abstração e reutilização em alto nível. Os exemplos do mundo real (pessoas, frutas, carros, etc.) são bons para ensinar a teoria, pois aproximam-se do cotidiano e são intuitivos. Todavia, programação não é sobre frutas......... Vamos as definições de classes abstratas e interfaces (específico em PHP, isso varia nas linguagens): Interfaces - Definem um tipo - Não são instanciáveis - Podem estender outras interfaces (quantas quiserem) - Podem definir constantes (não é recomendado) - Podem definir métodos públicos abstratos - Classes podem implementar quantas interfaces quiserem - Interfaces são um contrato para classes seguirem Classes abstratas - Definem um tipo, assim como classes normais - Não são instanciáveis - Podem estender outra classe (abstratas ou não) - Podem implementar interfaces - Podem definir métodos abstratos, públicos e protegidos - Podem definir constantes - Podem definir propriedades e métodos normais, exatamente como as classes concretas fazem - Classes abstratas são usadas através de herança das classes concretas Na prática - Você dificilmente cria uma classe abstrata de "primeira". Elas costumam ser criadas durante refatorações para reduzir repetição de código quando você tem 2 ou mais classes com comportamentos parecidos e que são do mesmo tipo. - Interfaces são uma mão na roda para abstrair o código e fazer polimorfismo. - Não substitua interfaces por classes abstratas, use ambas (na maioria dos casos). Compartilhar este post Link para o post Compartilhar em outros sites
Hive Pass 2 Denunciar post Postado Agosto 8, 2013 Voce tem certeza sim uai, o metodo é publico... Isso não significa confiança. ;) Bem, você está preso em conceitos e com dificuldades em compreender a real utilização disso. Na realidade sempre foi assim, rsrs. Teoria é "simples" de compreender, mas quando colocado em prática, em um problema real, as coisas mudam. Mas chegaremos lá. :graduated: O problema é que é dito que a intenção da orientação a objetos é aproximar o código ao mundo real, mas na verdade não é. O objetivo da OOP é possibilitar uma abstração e reutilização em alto nível. Os exemplos do mundo real (pessoas, frutas, carros, etc.) são bons para ensinar a teoria, pois aproximam-se do cotidiano e são intuitivos. Todavia, programação não é sobre frutas......... Eu entendo, sempre tive isso em mente, afinal a gente não vai criar uma vaca na internet. :( (bem que eu queria) Eu acho que assim, o conceito da orientação a objeto tem fundamentos parecidos com conceitos do mundo real (herança, por exemplo), por isso essa aproximidade e usar coisas reais da nossa vida para dá exemplos (creio que pegar por exemplo, um sistema REST para explicar para um iniciante não é interessante). Mas obrigado por fixar isso, compreendo o que você falou e concordo. Interfaces - Definem um tipo - Não são instanciáveis - Podem estender outras interfaces (quantas quiserem) - Podem definir constantes (não é recomendado) - Podem definir métodos públicos abstratos - Classes podem implementar quantas interfaces quiserem - Interfaces são um contrato para classes seguirem Classes abstratas - Definem um tipo, assim como classes normais - Não são instanciáveis - Podem estender outra classe (abstratas ou não) - Podem implementar interfaces - Podem definir métodos abstratos, públicos e protegidos - Podem definir constantes - Podem definir propriedades e métodos normais, exatamente como as classes concretas fazem - Classes abstratas são usadas através de herança das classes concretas Muito bom, realmente. :joia: Acho que isso é uma coisa que você deve ter sempre em mente, e quando você chegar diante de uma situação e você se perguntar qual o problema, consequentementevocê saberá qual utilizar (isso se aplica também para várias outras coisas, exemplo: Design Patterns) Na prática - Você dificilmente cria uma classe abstrata de "primeira". Elas costumam ser criadas durante refatorações para reduzir repetição de código quando você tem 2 ou mais classes com comportamentos parecidos e que são do mesmo tipo. - Interfaces são uma mão na roda para abstrair o código e fazer polimorfismo. - Não substitua interfaces por classes abstratas, use ambas (na maioria dos casos). Muito bom, já tinha isso em mente também, mas como estamos usando exemplos mais simples não achei interessante focar nisso agora. Outra coisa que eu aprendi é que normalmente você saberá a hora de utilizar um ou outro ou ambos é quando você faz testes. Quando entrar na etapa "B", etapa para refatorar você vai perceber a hora de utilizar. Perguntas: abstract class AbstractBasket { protected $basket = array(); public function add( $element ) { if( $this -> accept( $element ) ) { $this -> basket[] =& $element; } return $this; } abstract protected function accept( $element ); }Isso por algum acaso é um padrão de projeto? :oEu vejo ele sendo utilizado em vários casos. Ninguém respondeu essa pergunta :cry: Vejo muito o pessoa no Hangout falando sobre a questão de camadas (persistência, transferência, validação), como funciona a interação entre essas camadas? Vamos fazer uma suposição: o index é terra plana, onde é seguro está, e outras camadas fazem parte do oceano. Quando eu entrar em uma camada que fica no "meio do oceano", como eu vou "sair" dela ou utilizar outra sem ter um intermédio (terra plana) para eu poder ir até ela ou utilizar ela? Entramos ai em Design Patterns? Compartilhar este post Link para o post Compartilhar em outros sites
Enrico Pereira 299 Denunciar post Postado Agosto 8, 2013 Isso não significa confiança. ;) Na verdade, significa sim. Exemplo abaixo: abstract class AbstractDatabase { public function exec($query) {} } class MySQL extends AbstractDatabase {} class SQLite extends AbstractDatabase {} class Storage { public function __construct(AbstractDatabase $db) { $db->exec('SELECT * FROM users'); } } Um AbstractDatabase sempre terá o método exec, porque não é possível remover métodos. abstract class AbstractBasket { protected $basket = array(); public function add( $element ) { if( $this -> accept( $element ) ) { $this -> basket[] =& $element; } return $this; } abstract protected function accept( $element ); }Isso por algum acaso é um padrão de projeto? :oEu vejo ele sendo utilizado em vários casos. Lembra o Visitor, mas não é a implementação descrita dele. --- Sobre a pergunta de como integrar as camadas, isso é organização do projeto e design patterns ajudam sim. Sugiro que veja Domain Driven Design. Compartilhar este post Link para o post Compartilhar em outros sites
cristianoolv 93 Denunciar post Postado Agosto 8, 2013 Classes abstratas não podem ser instâciadas, e como a UNICA forma de a usar é com herança, então como TODOS metodos e propriedades publicas e abstratas não necessariamente herdades pela classe filha.. Compartilhar este post Link para o post Compartilhar em outros sites
Hive Pass 2 Denunciar post Postado Agosto 8, 2013 @Enrico Pereira Em todos os casos? E em classes de tipos iguais, mas com comportamentos diferentes Em todos os casos? E em casos comportamentais? Exemplo: Por mais que um Celta seja um Carro, ele não funciona da mesma maneira que todos os outros carros. Respondi você depois para evitar continuarmos com o assunto acima. Sobre a pergunta de como integrar as camadas, isso é organização do projeto e design patterns ajudam sim. Sugiro que veja Domain Driven Design. Vou dá uma olhadinha depois. Obrigado Mestre :worship: Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Agosto 9, 2013 Tópico limpo, brinquem sem brigar. Os dois!Bom... Olhando as interfaces e classes abstratadas (sem comportamento) elas são a mesma coisa, MAS é errado. Não é porque ambas são iguais que eu devo utilizar qualquer uma. Porque?Quem fala, fala alguma coisa. Logo pensamos que "falar alguma coisa" pode ser algo que pode variar referente a vários aspéctos, como: País, "problemas de voz" - disfemia e afins, localidade (Nordestino ou Carioca) há variações, logo a gente não poderia declarar uma classe abstrata e sim um contrato (interface) para que a pessoa possa variar a fala de acordo com o gosto dela e outros fatores. Como as interfaces só aceitam métodos públicos, elas descrevem melhor uma ação que todo objeto deve fazer. Já os métodos abstratos aceitam quaisquer das três visibilidades (tá... não tenho certeza quanto ao private) e além de descrever uma ação de que o objeto deve fazer elas descrevem um comportamento que o objeto deve ter.Programaticamente falando, não há diferença entre um método público de interface e um método abstrato público. É tudo uma questão de conceito.Por preferência e ponderação pessoal, quando seguindo essa linha de raciocínio:- Se um método só pode ser acessado internamente à classe, em contexto de herança, e existe exigência de diferentes implementações por parte da classe abstrata, o método só pode ser protected e, logo, também abstract- Se um método pode ser invocado a nível de instância, ele deve ser public e um método público tem sua assinatura (e não sua implementação) conhecida pelo usuário, sendo assim, fecha contrato com uma interface.Ou seja, nunca tenho métodos abstract public e, obviamente, nem abstract privateNem sei se isso é possível de se declarar, de tão absurdo que é. :unsure:Porém, nem sempre isso vai ser uma regra.Em casos raros, para evitar um Syntatic Sugar, ganhar uma certa performance e/ou evitar ficar dando voltas e mais voltas no código, se você precisa garantir a existência de um determinado método mas não justifica uma herança ou o cenário de uma abstração terminaria num único método abstrato, use uma interface.Nesses casos, é preferível ter uma lógica interna que deveria ser protected definida como public.Se você precisa garantir a existência de um método público e puder determinar mais de uma rotina que se repete entre múltiplos objetos de um mesmo grupo, abstraia o que for comum e estenda. Interfaces- Podem definir constantes (não é recomendado) Eu ia dizer que discordo, mas resolvi pesquisar um pouco antes e cheguei num consenso de que isso é um pouco controverso. Essa posição, conhecida como Constant Interface Antipattern, é um conceito praticado mais no Java do que no PHP e está intrinsecamente ligado à API de um sistema, onde um determinado comportamento não deve ser exposto publicamente.Faz sentido, se entendido corretamente. Mas os exemplos desse anti-pattern nem sempre são bons ou nem sempre explicam de forma suficientemente clara o que ele realmente é.Definir constantes de interface não é errado. Errado é definir uma interface de constantes. Tem diferença.Uma constante de interface define uma característica imutável de um objeto. Mas um objeto não é feito apenas de características, mas também de comportamentos descritos pelos seus métodos.Sendo assim, o anti-pattern existe em definir uma interface feita unicamente de constantes, sem métodos. Uma ressalva que eu acho válida, no entanto, é uma interface composta apenas de constante MAS que estenda outra(s) interface(s) estas sim com um ou mais métodos.Por exemplo, eu tenho um conjunto de classes de Validação e todos os algorítimos respeitam a interface Validate: <?php interface Validate { /** * Validates given Character Set * * @param string $data * Data to Validate */ public function validate( $data ); } Então eu tenho um conjunto de Validadores que por serem de um tipo próprio específico definem uma interface própria que estende essa acima.E essa é uma interface feita apenas de constantes, mas pelo fato de estender uma outra que possui ao menos um método, não caracteriza o anti-pattern. Compartilhar este post Link para o post Compartilhar em outros sites
cristianoolv 93 Denunciar post Postado Agosto 9, 2013 Nem sei se isso é possível de se declarar, de tão absurdo que é. Não não é, metodos abstratos são obrigados a serem reescritos, e como não tem como reescrever metodos privados... nunca tenho métodos public abstract ??? Por que não ? Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Agosto 9, 2013 nunca tenho métodos public abstractÉ muito fácil cagar regras. Teoricamente, vc não deve declarar métodos públicos abstratos numa classe porque eles deveriam ir numa interface. Lendo este tópico, tem muita coisa que é linda na teoria, mas na prática não funciona. OO não é teoria, você só aprende praticando. Claro que um embasamento teórico é importante, mas ele por si só não vai garantir nada. Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Agosto 9, 2013 Teoricamente, vc não deve declarar métodos públicos abstratos numa classe porque eles deveriam ir numa interface. Olha, talvez lá no fundo eu sempre tive esse pensamento, mas confesso que pelo menos de início, foi puramente por estética do código. :P Hoje já não faço isso nem tanto porque "é coisa de interface" mas também porque ainda não fiquei convencido quanto a usar classes abstratas como tipo. Compartilhar este post Link para o post Compartilhar em outros sites
Evandro Oliveira 331 Denunciar post Postado Agosto 9, 2013 Aviso: post longo.Apenas me sincronizando com o tópico... Daqui pra frente respondo quando possível. abstract class Pessoa { public function falar($mensagem) { echo $mensagem; }}Mesmo que você possa estender e sobrescrever esse método você passa a não ter uma coisa essêncial na orientação a objetos: A confiança. - Por "falar" na classe abstrata não ser "abstrata" e ter um comportamento, ela não está FORÇANDO a classe filha ter esse método, logo eu passo a não saber, ter uma certeza de que "uma pessoa fala". Entra a questão da herança. Subclasses de [inline]Pessoa[/inline] não precisam implementar [inline]falar()[/inline] porque elas herdam de [inline]Pessoa[/inline]. O simples fato da assinatura existir tanto em [inline]protected[/inline] quanto [inline]public[/inline] implica que subclasses sejam "FORÇADAS" a ter o método/propriedade. Um exemplo errado da utilização de interfaces foi o erro meu de criar uma interface "Basket" para outras definições/nomes/coisas que são uma cesta, como Cesta de Frutas ou de Café da Manhã, que foi corrigido pelo @Bruno Augusto. Depende do ponto de vista. Não sei nem se erro, talvez um equívoco. Eu posso dizer que cesta pode ser tudo aquilo onde você coloca e retira coisas para que possam ser transportadas. Isso vale para cestas de café da manhã e para potes de sorvete com frutas. Mas não vale para as cestas de basquete, por exemplo.Logo mais à frente você mesmo percebeu... Podemos dizer que Basket (Cesta) não é algo que "muda", é algo fixo/sólido com uma definição única: Adicionar algo ou tirar algo.Logo podemos dizer que qualquer tipo de cesta, independente se ela é Cesta de Café da Manhã ou de Frutas, elas sempre tiram e colocam algo da mesma forma, mas com "dependências". Podemos falar que é uma generalização? Creio que sim. mas... abstract class AbstractBasket { protected $basket = array(); public function add($element) { if($this -> accept( $element ) ) { $this -> basket[] =&$element; } return $this; } abstract protected function accept( $element ); }Eu estou errado em alguma coisa, ou eu realmente entendi a diferença entre as duas? rsrs. Como eu havia dito, cestas de basquete não se enquadram no cenário. interface Basket { public function add ($item); } interface NotABasketballBasket { public function remove ($item); Mas, como eu também havia dito, é uma questão de ponto de vista interface Basket { public function add ($item); public function remove ($item); } abstract class BasketballBasket implements Basket { final public function remove($item) { throw new BadMethodCallException( "Basketball baskets doesnot hold items!" ); } Em todos os casos? E em casos comportamentais? Exemplo: Por mais que um Celta seja um Carro, ele não funciona da mesma maneira que todos os outros carros. Again, ponto de vista. Defina um carro e defina um cenário onde um Celta não atenda à definição de carro. O que pode ser verdadeiro é o caso do Celta não ser um carro de luxo, por exemplo. interface Carro { public function andar(); public function parar(); } interface CarroDeLuxo { public function reclinarBancosDeCouro($angulacao); 1 - Porque que quando eu não declaro uma propriedade, mas dentro de um método eu faço isso e funciona: <?php class WithoutProperty{ public function setProperty($property) { $this->property = $property; } public function getProperty() { return $this->property; } } Questão de escopo (não poder declarar de fora da classe) e retrocompatibilidade (poder declarar de dentro da classe). 2 - Qual a “função” de um método set e um get?A pergunta deve ser meia sem nexo, mas vamos aos fatos.Vamos supor que eu tenho um carro, mas existem vários modelos correto? Então (Exemplo simples apenas explicando onde eu quero chegar): <?php interface Carro{ public function setCarModel($model); public function getCarModel(); } class Corsa implements Carro{ private $model; public function setCarModel($model) { $this->model = $model; } public function getCarModel() { return $this->model; } } $Corsa = new Corsa(); $Corsa->setCarModel("G1");Por mais que tenha sentido a classe Corsa implementar a interface Carro, qual a lógica dos métodos get e set sendo que eles só fazem uma função simples? – Por mais que a propriedade seja private, o que impede de mudar para public e fazer assim, sendo que o set faz praticamente a mesma coisa? class Corsa implements Carro{ public $model; [...] } $Corsa = new Corsa(); $Corsa->model = "G1"; Com um exemplo cru, assim, fica difícil explicar. Mas, e se eu fizer isso... class Person { public $age; } $lady = new Person(); $lady->age = "A lady never tells"; No caso de setters, o objetivo é validação. Um setter que aceita qualquer coisa e define isso como valor perde o sentido de existir, realmente. O mesmo se aplica com o get. Qual a finalidade dele em um método apenas com return sendo que eu posso acessar ele diretamente? – Caso ele seja public, é claro. A principal funcionalidade do getter é retornar o valor, uma vez que o mesmo não é mais acessível. Estão trabalhando nisso. Mas nada impede que possamos utilizar lógica nos getters também... class Escalator { private $persons; public function __construct() { $this->persons = new SplFixedArray(8); } private function getPersonPosition(Person $person) { foreach ($this->persons as $position => $inside) { if ($person === $inside) { return $position; } } return null; } public function putIn(Person $person) { if (!is_null($this->getPersonPosition($person)) { throw new InvalidArgumentException( sprintf("%s is already inside.", $person->getName()) ); } $this->persons[] = $person; } public function putOut(Person $person) { if (is_null($this->getPersonPosition($person)) { throw new InvalidArgumentException( sprintf("Can't kick out %s. Not here.", $person->getName()) ); } } public function getWeight() { $weight = 0; foreach ($this->person as $person) { $weight += $person->getWeight(); } return $weight; } 3 - Continuando no questão de get e set: Entrando um pouco em visibilidade também. Um método privado está falando que ele não pode ser acessado externamente e nem por classes que herdam ela correto? Então, qual a lógica de ter um método (set) para alterar essa variável sendo que se eu quero que ela seja privada, não é apenas para eu alterar ou acessar ela dentro do meu escopo e não de fora(set)? Novamente, validação. $contribuinteDaReceita->cpf = "Não te interessa!"; E se um set ou get fosse para validar o que está entrando na classe? A interface seria inútil? E o "conceito" de que Corsa é um Carro?Devem definir comportamentos:Ok; Carro pode ter um comportamento: Andar(), mas e uma fruta? Qual seria a ação de uma fruta? Crescer? Amadurecer? Apodrecer? Adoecer? Aplicar pesticida/fungicida? Abacate é uma fruta logo ela iria implementar Fruta correto? Mas qual a lógica de ter uma interface sem "comportamento" interface Fruit { public function countSeeds(); } class Avocado implements Fruit{ public function countSeeds() { return 1; } } class Papaya implements Fruit{ public function countSeeds() { throw new LengthException("Who knows?"); } } Mas qual a lógica de ter uma interface sem "comportamento" <?php interface Fruta {} class Abacate implements Fruta{} Seguindo essa linha de pensamento, nenhuma. Mas se você pensar pelo lado de polimorfismo, tem todo sentido. Em algum momento nessa discussão, vocês implementaram um método [inline]accepts[/inline] para fazer a validação do que vai dentro da cesta. Se você deixar este tipo de validação por conta da implementação, uma hora você vai acabar com isso aqui: class FruitBasket implements Basket { public function accepts($item) { switch (get_class($item)) { case "Avocado"; case "Papaya"; case "Strawberry"; // ... return true; } return false; } } Quando você confia na interface, você abstrai esse tipo de validação da implementação e ganha uma flexibilidade indescritível interface FruitBasket { public function add(Fruit $item); } class Avocado implements Fruit {} class Strawberry implements Fruit {} class Papaya implements Fruit {} Eu assisto vários vídeos da imasters (hangouts) e também outros vídeos e sempre vejo eles falando de: Horizontal e Vertical. O que seria isso? Porque a classificação horizontal e vertical? Em qual momento é aplicado? Porque existem Frameworks classificados dessa maneira (Horizontal e Vertical)? Porque a Orientação a Objetos é horizontal? Duas palavras: Árvore genealógica.Herança é definida de cima para baixo. Diversidade no mesmo "nível" (mesma geração) são demarcadas lateralmente.Ainda vejo nos posts do fórum muitas dúvidas quanto à interface. Pra evitar repetição, segue uma citação e o link original, pra começar: $usuario = new UsuarioMapper();Beleza, campeão. Um mapeador de usuário para o quê? Pense em código semântico e auto-descritivo.em todos os [inline]*PdoMapper[/inline]. O problema aqui é querer se antecipar à implementação no âmbito da abstração. A estrutura e design de interfaces remete à abstração. Assumindo que é uma boa prática manter as propriedades privadas, Você - enquanto implementador de interfaces - não deve e não precisa saber quais os nomes foram utilizados para as propriedades de um objeto.Você se antecipa à implementação, cria uma propriedade chamada [inline]$pdo[/inline]. Eu estendo sua classe abstrata, sobrescrevo o construtor e faço function __construct(PDO $pdo){ $this->databaseConnectionInstance = $pdo;}Uso tudo em função de [inline]$databaseConnectionInstance[/inline] respeitando a interface. O sistema continua funcionando perfeitamente, como deve, e você teve trabalho à toa. Não sei como está o seu raciocínio agora. Mas, até o momento deste quote, você ainda não tinha sacado do que se trata uma interface. Interface por vezes também é chamada de tipo. A interface define o tipo da instância. A interface não é apenas o elemento que nós descrevemos no código sob a palavra chave [inline]interface[/inline]. Interface é o resultado final de todas as estruturas que compõem uma instância.Assim, assumindo interface Foo{ public function foo();} interface Bar{ public function bar()/} class Baz implements Foo, Bar{ public function foo() { echo 'foo'; } public function bar(); { echo 'bar'; }}A interface de [inline]Baz[/inline] é............. [inline]Baz[/inline]! Isso mesmo! Interface é a mesma coisa que tipo. A interface é o tipo do objeto. A variável [inline]$nomeDaVariável[/inline] contém uma instância do tipo [inline]nomeDaInstancia[/inline]. O ponto crucial aqui é a palavrinha chave [inline]implements[/inline]. Isso quer dizer que objetos do tipo [inline]Baz[/inline] implementam [inline]Foo[/inline] e [inline]Bar[/inline]. Pra resumir, no final das contas, a interface é o resultado final da salada toda. Interface remete a comportamento e expectativa. Por isso há a repetição de termos como contrato e confiança, respectivamente. Quando você programa para uma interface, você espera que uma instância se comporte da forma como ela se propôs a fazer quando disse que implementava a interface que você espera.Anteriormente, você disse que um Celta pode até ser um carro, mas também pode não fazer a mesma coisa que todos os outros carros. Como resposta, pedi que você definisse um carro.Para mim, um carro é um veículo automotor que podemos - pra ser sucinto - [inline]andar[/inline] e [inline]parar[/inline]. Não vem ao caso coisas como abastecer, abrir/fechar/trancar portas e etc. Só vai esticar um post que já está enorme.Se eu posso entrar, andar, parar e sair pra me locomover é um carro. Não por acaso, os vagões dos trens são também chamados de carros. Os ônibus de transporte coletivo são chamados de carro. Porque atendem às minhas expectativas do que eu espero de um carro. Isso é a interface. Isso é o tipo. Celta é um tipo de carro. O vagão do trem é um tipo de carro. O ônibus é um tipo de carro. Compartilhar este post Link para o post Compartilhar em outros sites
Tereza Marta 1 Denunciar post Postado Agosto 9, 2013 Será que essa minha consulta poderia ser feita com orientação a objeto? http://forum.imasters.com.br/topic/505911-otimizar-mltiplos-selects-em-tabela-mysql/ Compartilhar este post Link para o post Compartilhar em outros sites
Enrico Pereira 299 Denunciar post Postado Agosto 9, 2013 IMHO, interfaces vazias fazem sentido porque elas, apesar de serem vazias, sempre serão um tipo. Quando há um monte de classes que têm a mesma função executada de modos distintos (ex: MysqlConnection, SQLiteConnection, etc.) e não há uma tipificação comum delas não está havendo muito sentido nisso. Se criarmos uma interface Connection e fazermos as classes de conexão implementá-las, nós estamos melhorando a própria organização do código, afinal estamos tipificando elementos comuns, e não necessariamente precisamos adicionar métodos à interface. Interfaces, além de serem contratos, são uma representação de um grupo. Estão trabalhando nisso. Evandro, esta RFC não é mais mantida. Houve uma nova versão nova deste RFC que já foi votada e infelizmente como era uma feature que expandiria a linguagem, precisava de dois terços de aprovação dos membros votantes, mas não conseguiu essa marca.. acho que não vai rolar essa de accessors no PHP tão cedo :(. Nem sei se isso é possível de se declarar, de tão absurdo que é. :unsure: É como declarar uma classe abstrata e final :lol:. Um método privado e abstrato resultará em um fatal error "Abstract function Class::method() cannot be declared private in...". --- Eu vejo classes abstratas como uma base de comportamento para uma interface. Exemplo: // Uma interface p/ qualquer storage de sessão interface SessionStorage { public function save($key, $value); } // Um storage que armazena os dados de sessão em arquivos class FileSessionStorage implements SessionStorage { public function save($key, $value) {} } // Um storage que armazena os dados de sessão no MongoDb class MongoSessionStorage implements SessionStorage { public function save($key, $value) {} } // Uma classe abstrata para servir de base para storages que armazenam os dados de sessão em banco de dados que possam ser utilizados através do PDO abstract class PdoSessionStorage implements SessionStorage { public function save($key, $value) {} } // Um storage que armazena os dados de sessão no MySql através de PDO, por isso estende a classe abstrata PdoSessionStorage class MySqlSessionStorage extends PdoSessionStorage {} // Um storage que armazena os dados de sessão no SQLite através de PDO, por isso estende a classe abstrata PdoSessionStorage class SQLiteSessionStorage extends PdoSessionStorage {} Uma classe abstrata, para mim, está entre uma interface e uma classe concreta. Será que essa minha consulta poderia ser feita com orientação a objeto? http://forum.imasters.com.br/topic/505911-otimizar-mltiplos-selects-em-tabela-mysql/ Orientação a objetos não é igual a um frango frito do KFC que você compra, come e pronto. Orientação a objetos é um paradigma complexo, completo e com uma infinidade de possibilidades e padrões. Você não faz "uma consulta" usando OOP. OOP não é uma ferramenta que você usa como uma IDE ou uma biblioteca, por exemplo. É todo um conceito, um pensamento, uma abordagem para solução de problemas. Compartilhar este post Link para o post Compartilhar em outros sites
Hive Pass 2 Denunciar post Postado Agosto 9, 2013 @Henrique Barcelos Teoricamente, você não deve declarar métodos públicos abstratos numa classe porque eles deveriam ir numa interface. Vamos supor que eu tenho uma classe abstrata e ela tem uma responsabilidade, nisso eu tenho que declarar um método público abstrato para as classes filhas. Eu não devo fazer isso por ser responsabilidade das interfaces? Ou eu entendi totalmente errado? Lendo este tópico, tem muita coisa que é linda na teoria, mas na prática não funciona. OO não é teoria, você só aprende praticando. Claro que um embasamento teórico é importante, mas ele por si só não vai garantir nada. Realmente, mas teoria também é muito importante.Muita gente aprende a programar na marra, praticando e não entende da teoria.Veja o assunto do tópico no momento, a questão de classes abstratas e interfaces, que eu, particulamente, acho uma das coisas mais (se não a mais) díficeis da orientação a objetos.Quando você aprende a programar apenas na prática você pode fazer mais cagada do que sabendo a teoria, porque na teoria ela explica em quais momentos devemos utilizar.Então é meio que um conjunto, Teoria & Pratica.@Evandro Oliveira Entra a questão da herança. Subclasses dePessoa não precisam implementar falar() porque elas herdam de Pessoa. O simples fato da assinatura existir tanto em protected quanto public implica que subclasses sejam "FORÇADAS" a ter o método/propriedade. Realmente, sem dúvida, mas vamos criar a seguinte hipótese.Eu estou criando um sistema para banco de dados, mas para criar eu preciso abstrair o problema. Mas o que é abstração: Abstração é a habilidade de concentrar nos aspectos essenciais de um contexto qualquer, ignorando características menos importantes ou acidentais. Em modelagem orientada a objetos, uma classe é uma abstração de entidades existentes no domínio do sistema de software. Logo eu tenho em mente que eu não devo me preocupar de qual forma ele vai salvar o dado, o meu sistema tem que ter a capacidade de salvar independente de como. Correto?Agora vamos supor que eu crio uma classe abstrata com um método publico exec. abstract class AbstractDatabase { public function exec($query) {} } Temos um "tipo/contrato" para todos os outros que forem um banco de dados "assinarem", temos até ai a certeza de que todas TERÃO o método "exec". Ótimo!Por mais que eu tenha a certeza de que o método é publico (uma confiança), essa confiança não é de certo ponto verdadeira.Porque?Eu tenho mais uma classe no sistema que é para uso geral para conectar com qualquer banco de dados. Logo eu tenho a certeza de ter o método exec dentro de todos os drivers de banco de dados que assinaram "AbstractDatabase". Mas temos uma questão, nem todos os drivers se comportam iguais, logo o filho iria sobrescrever o método do pai "exec".Como eu não sei quais os drivers que o meu usuário criou, seja ele para Postgre ou MySQL, onde isso é algo mutável e por esse motivo ele pode muito bem fazer uma cagada por não ter algo obrigatório a ser implementado.imagine... class MySQL extends AbstractDatabase { public function($exec, $callback) {} } Passamos ai a ter um erro? Sim! Warning: Missing argument 2 O que seria diferente de interface, onde eu estou obrigado a todos os "exec" por mais que trabalhem diferentes, eles tenham os mesmos parametros. interface AbstractDatabase { public function exec($query); } class MySQL implements AbstractDatabase { public function exec($query, $callback) { echo $query; } } class DatabaseConnection { public function __construct(AbstractDatabase $db) { $db->exec('SELECT * FROM users'); } } new DatabaseConnection(new MySQL()); Fazendo isso temos um erro: Fatal error: Declaration of MySQL::exec() must be compatible with AbstractDatabase::exec($query) on line 7 Veja que esse erro é causado pelo usuário e não pelo meu sistema, então ele terá que corrigir. Então: class MySQL implements AbstractDatabase { public function exec($query) { echo $query; } } Eu tenho a certeza de que o método "exec" de qualquer driver criado vai funcionar PERFEITAMENTE independente de qual banco de dados. Era nisso que eu queria chegar. Não sei se entenderam.Eu vejo que um método publico em uma classe abstrata é como uma forma de "substituição" para algo que não temos certeza da implementação.Afinal, classes abstratas não podem ser instanciadas, logo não faz sentido ter métodos publicos, apenas para classes que as irão instanciar.Além de uma forma de substituição, a questão da reutilização, para não precisar reecrever o mesmo método várias vezes para classes filhas, temos apenas uma na classe pai.----Sobre o resto da postagem: Simplesmente PERFEITO!@Enrico Pereira IMHO, interfaces vazias fazem sentido porque elas, apesar de serem vazias, sempre serão um tipo. Quando há um monte de classes que têm a mesma função executada de modos distintos (ex: MysqlConnection, SQLiteConnection, etc.) e não há uma tipificação comum delas não está havendo muito sentido nisso. JUSTAMENTE, isso que eu estou falando.Há 2 partes de uma aplicação: A parte do seu sistema (parte que eu conheço) e aparte na qual o cliente(s) ou outro(s) programador(s) vai utilizar trabalhar (não tenho conhecimento geral sobre ele, não tenho bola de cristal).Se você cria interfaces para os cliente(s) e programadore(s) trabalhem em cima, você tem a segurança, a confiança de poder chamar um método que você tem a certeza da implementação, tanto na entrada, quando na saida.Veja meu código acima. Se criarmos uma interface Connection e fazermos as classes de conexão implementá-las, nós estamos melhorando a própria organização do código, afinal estamos tipificando elementos comuns, e não necessariamente precisamos adicionar métodos à interface.Interfaces, além de serem contratos, são uma representação de um grupo. Justamente, vejo dessa forma também. Evandro, esta RFC não é mais mantida. Houve uma nova versão nova deste RFC que já foi votada e infelizmente como era uma feature que expandiria a linguagem, precisava de dois terços de aprovação dos membros votantes, mas não conseguiu essa marca.. acho que não vai rolar essa de accessors no PHP tão cedo :(. Eu dei uma lida, e gostei. :D Uma classe abstrata, para mim, está entre uma interface e uma classe concreta. Boa! Esse tópico está muito rico. Parabéns pessoal. Compartilhar este post Link para o post Compartilhar em outros sites
Evandro Oliveira 331 Denunciar post Postado Agosto 9, 2013 Logo eu tenho em mente que eu não devo me preocupar de qual forma ele vai salvar o dado, o meu sistema tem que ter a capacidade de salvar independente de como. Correto? bingo! Agora vamos supor que eu crio uma classe abstrata com um método publico exec. abstract class AbstractDatabase { public function exec($query) {} } Temos um "tipo/contrato" para todos os outros que forem um banco de dados "assinarem", temos até ai a certeza de que todas TERÃO o método "exec". Ótimo! Por mais que eu tenha a certeza de que o método é publico (uma confiança), essa confiança não é de certo ponto verdadeira. Porque? Eu tenho mais uma classe no sistema que é para uso geral para conectar com qualquer banco de dados. Logo eu tenho a certeza de ter o método exec dentro de todos os drivers de banco de dados que assinaram "AbstractDatabase". Mas temos uma questão, nem todos os drivers se comportam iguais, logo o filho iria sobrescrever o método do pai "exec". Sobrescrita é diferente de sobrecarga. O manual do PHP errôneamente afirma possuir suporte a sobrecarga de métodos. Como eu não sei quais os drivers que o meu usuário criou, seja ele para Postgre ou MySQL, onde isso é algo mutável e por esse motivo ele pode muito bem fazer uma cagada por não ter algo obrigatório a ser implementado. imagine... class MySQL extends AbstractDatabase { public function exec($query, $callback) {} } Passamos ai a ter um erro? Sim! PHP Strict standards: Declaration of MySQL::exec() should be compatible with AbstractDatabase::exec($statement) in php shell code on line 5 Eu vejo que um método publico em uma classe abstrata é como uma forma de "substituição" para algo que não temos certeza da implementação. Vejo dois cenários: Fallback de implementação: Se você não implementar a SUA forma de executar este método, a forma "padrão" será assumida Especialização de interfaces: Reveja o exemplo da cesta de basquete que emite uma exceção ao tentar remover itens. Uma vez que há cenários para implementação, é obrigação da linguagem fornecer todo o suporte necessário para esta implementação. Daí o motivo de ser possível declarar métodos/propriedades privados em classes abstratas. Afinal, classes abstratas não podem ser instanciadas, logo não faz sentido ter métodos publicos, apenas para classes que as irão instanciar. Além de uma forma de substituição, a questão da reutilização, para não precisar reecrever o mesmo método várias vezes para classes filhas, temos apenas uma na classe pai. Releia o meu quote que não pertence a este post. Lá eu falo do "problema" que é querer se antecipar à implementação. Você está indo exatamente na contramão da orientação a objetos. O objetivo aqui é exatamente se preocupar em prover o "manual de instruções" da sua modelagem. Quando você procura um manual, você quer saber como você usa aquele item. Não como ele foi construído. Há 2 partes de uma aplicação: A parte do seu sistema (parte que eu conheço) e aparte na qual o cliente(s) ou outro(s) programador(s) vai utilizar trabalhar (não tenho conhecimento geral sobre ele, não tenho bola de cristal). ... e é exatamente por isso que você implementa o mínimo possível. Compartilhar este post Link para o post Compartilhar em outros sites
Enrico Pereira 299 Denunciar post Postado Agosto 9, 2013 Eu não devo fazer isso por ser responsabilidade das interfaces? Ou eu entendi totalmente errado? Usando o vocabulário de que uma classe abstrata é uma especialização de uma interface, só que não concreta, podemos ter a noção de que os métodos públicos abstratos das classes abstratas são os método(s) requerido(s) pela(s) interface(s) que as classes abstratas não puderam abstrair, por ser específico para a classe concreta, exemplo: interface Header { public function getName(); public function getValue(); } abstract class SimpleHeader implements Header { private $value; public function __construct($value) { $this->value = $value; } public function getValue() { return $this->value; } // Note a ausência do getName, que é abstrato por causa da interface } class Pragma extends SimpleHeader { public function getName() { return 'Pragma'; } } class TransferEncoding extends SimpleHeader { public function getName() { return 'Transfer-Encoding'; } } Eu estou criando um sistema para banco de dados, mas para criar eu preciso abstrair o problema. Se você está criando um sistema para banco de dados, não é abstrato. Você deve criar um sistema que seja capaz de suportar banco de dados. Logo eu tenho em mente que eu não devo me preocupar de qual forma ele vai salvar o dado, o meu sistema tem que ter a capacidade de salvar independente de como. Correto? Perfeito. É exatamente este o objetivo da abstração. Agora vamos supor que eu crio uma classe abstrata com um método publico exec. abstract class AbstractDatabase { public function exec($query) {} } Temos um "tipo/contrato" para todos os outros que forem um banco de dados "assinarem", temos até ai a certeza de que todas TERÃO o método "exec". Ótimo! Para isso, use interfaces. Isso é mais até conceitual do que este tal de "contrato" que estamos falando. Nós usamos interfaces para ter este contrato de forma mais elegante. O contrato já existe na verdade, estamos apenas o explicitando, o que é bom. Você está viajando um pouco nessa de "contrato", tome cuidado. Mas temos uma questão, nem todos os drivers se comportam iguais, logo o filho iria sobrescrever o método do pai "exec". Como eu não sei quais os drivers que o meu usuário criou, seja ele para Postgre ou MySQL, onde isso é algo mutável e por esse motivo ele pode muito bem fazer uma cagada por não ter algo obrigatório a ser implementado. É por isso que não se usa classes abstratas diretamente. Tenha suas interfaces antes de partir para classes abstratas. Comece do mais simples para o mais complicado, não o contrário. Passamos ai a ter um erro? Sim! Este é o contrato natural: duck-typing. Se você não torna suas interfaces explícitas, elas vão existir, de uma forma ou de outra. --- Ao geral do post: você não implementar o método x ou implementar o método x com uma diferente assinatura é o mesmo problema, a violação do contrato. Há 2 conceitos populares a serem explorados: "Favor composition over inheritance" e "Program to an interface, not an implementation". Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Agosto 10, 2013 Quando eu postei o exemplo corretivo/melhorado das Cestas, nem me ocorreu uma cesta de basquete porque estávamos falando de contêineres de items. Mas agora que mencionou, já que uma cesta de basquete não permite que itens sejam removidos, ela sequer guarda items, logo, bastaria disparar a Exception nua e crua em AbstractBasket::accept(). Compartilhar este post Link para o post Compartilhar em outros sites
Evandro Oliveira 331 Denunciar post Postado Agosto 10, 2013 Mas agora que mencionou, já que uma cesta de basquete não permite que itens sejam removidos, ela sequer guarda items, logo, bastaria disparar a Exception nua e crua em AbstractBasket::accept(). Mas uma cesta de basquete aceita bolas de basquete e ainda precisa implementar a lógica de atualizar o placar. Compartilhar este post Link para o post Compartilhar em outros sites
Hive Pass 2 Denunciar post Postado Agosto 10, 2013 Pessoal prometo responder as postagens de vocês, mas antes eu vou fazer algumas coisas como: 1 - Ler novamente todo o tópico para tentar compreender perfeitamente o que vocês estão falando para mim para não ficar algo repetitivo, vocês tentando explicar, eu lendo rapidamente não entendo e voltando a perguntar. 2 - Pegar citações (fragmentos) que vocês falaram como lazy loading, Prefer composition over inheritance, Design Principles, Syntatic Sugar, sobrecarga. fallback de implementação, especialização de interfaces, duck-typing, dentre outros que estão no tópico. O tópico está muito rico, com um conteúdo excelente, mas por ter um conteúdo muito grande e com várias opiniões sobre conceito de abstração, classes abstratas e interface acabei dando um nó na cabeça. Preciso parar para ler novamente o tópico e tentar formar algo sólido. Estou pensando em trazer algo real para aqui, tentar desenvolver algo como um sistema de log, ou validação, segurança, etc. Alguma dica? Podem me indicar artigos e livros que falam muito bem sobre o assunto em questão? Tanto em Pt-br quanto em En? - Procurar é facil, difícil é saber se presta. rsrs. Obrigado a todos pelas postagens. Obrigado por tirarem um tempinho para me ajudar. Espero que possamos continuar esse tópico ainda e extender o assunto dele. Responderei as postagens em breve. Compartilhar este post Link para o post Compartilhar em outros sites
01100011cc 15 Denunciar post Postado Agosto 10, 2013 Estou pensando em trazer algo real para aqui, tentar desenvolver algo como um sistema de log, ou validação, segurança, etc. Alguma dica? Faz um banco, com depositos, saques, variados tipos de conta... Compartilhar este post Link para o post Compartilhar em outros sites