Ir para conteúdo

Arquivado

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

Hive Pass

Orientação a Objetos - Perguntas e Respostas

Recommended Posts

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;
	
	}	

}


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";


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.

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)?

Por enquanto são essas perguntas, mas de acordo com que eu vou praticando e surgindo dúvidas eu vou perguntando.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A interface serve pra definir o comportamento de um objeto, logo não faz sentido, nem há motivo ter getters e settes nela.Quanto a private, serve para proteger dados internos da classe.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A interface serve pra definir o comportamento de um objeto, logo não faz sentido, nem há motivo ter getters e settes nela.Quanto a private, serve para proteger dados internos da classe.

 

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?

Abacate é uma fruta logo ela iria implementar Fruta correto? Mas qual a lógica de ter uma interface sem "comportamento"

 

<?php

interface Fruta {

}

class Abacate implements Fruta
{

}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Cara, você esta pensando muito em código..

 

Orientação a Objeto é conceito.

 

Getters e Setters é por que um método só processa algo enquanto uma propriedade é algo "estático" .

 

Trazendo o problema para o mundo real é simples, uma propriedade conseguiria se setar?

 

A resposta clara é não, existe um método que seta uma propriedade.

 

Quem executa qualquer ação é um método então se vc não tiver um getter e um setter como vc seta uma propriedade e recupera a mesma sendo que uma propriedade não pode executar nada?

 

 

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?

Não vai precisar disso por que você vai dizer ao objeto que ele sempre vai ter um veiculo logo é um ERRO enorme você dizer que uma banana é um carro.

 

tente sair do código e entrar mais em conceito.

trazer o problema para o mundo real e ver como "objetos físicos" se comportam.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A interface serve pra definir o comportamento de um objeto, logo não faz sentido, nem há motivo ter getters e settes nela.

 

Cuidado com essa afirmação. Apesar de que em Java interfaces podem ter comportamento (acho que você confundiu c/ Java), em PHP elas apenas definem contrato.

 

Interfaces são um tipo, que podem definir métodos para que um(as) classe(s) tenha que implementar.

É uma forma de abstrair e desacoplar o código com polimorfismo.

 

 

 

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;
	
	}	

}

 

Você não necessita declarar uma propriedade previamente. Todavia, essa propriedade será pública.

 

 

2 - Qual a “função” de um método set e um get?

 

Definir e recuperar um valor. Em algumas linguagens (como o PHP), eles são usados. Porém, em algumas há recursos melhores para isso.

 

Usamos getters/setters ao invés de propriedades públicas pois eles permitem validação, lazy loading, etc. Lista de razões aqui: http://stackoverflow.com/a/1568230

 

Em algumas linguagens, como o Ruby, eles não são necessários:

class User
  attr_accessor :name, :email
end

user = User.new
user.name = "Joãozinho"
user.email = "joao@pedefeijao.com"

puts user.name + "\n"
puts user.email + "\n"

 

 

 

Logo, depende da linguagem utilizada e de seu ecossistema.

E não simplesmente faça a IDE "vomitar" getters e setters por todo lado, pense bem antes de implementá-los.

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Vinicius Rangel

Obrigado pelas dicas.

Não é que eu não pense ou tente pensar em conceito, eu tento muito trazer para a vida real, mas a questão é que eu estou aprendendo ainda, e não é tudo que só porque eu trouxe para o mundo real que eu vou saber implementar. Justamente isso as perguntas.

@Enrico Pereira

Você não necessita declarar uma propriedade previamente. Todavia, essa propriedade será pública.


Realmente, percebi isso, mas depois que eu postei a pergunta. - Deixei apenas se alguém tivesse alguma resposta diferente. (Ninguém sabe né :P)

Muito obrigado pela lista de vantagens de usar setters and getters.

E não simplesmente faça a IDE "vomitar" getters e setters por todo lado, pense bem antes de implementá-los.


Eu tenho isso em mente, além de não ser algo interessante em questão de "boas práticas" getters and setters para todos os lados, mas também visualmente.

Tem alguma dica de momentos em qual devo utilizar e não utilizar? No seu ponto de vista ou de outros?

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)?


Ninguém respondeu :(

@edit

Encontrei uma penca de tópicos no stackoverflow sobre "getters setters". :o

 

http://stackoverflow.com/search?q=getters+setters

Compartilhar este post


Link para o post
Compartilhar em outros sites

O problema dos getters/setters é o modelo anêmico, este post deve ajudar-te: http://blog.caelum.com.br/nao-aprender-oo-getters-e-setters/

 

O normal é usar privado para todas as propriedades.

Há um conceito (não aplicável em todas linguagens) que é: Propriedades -> estado e Métodos -> operações e trocas de estado.

 

Na comunidade Java getters/setters é algo extremamente discutido.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vamos as próximas perguntas (lembrando que de acordo com que eu vou tendo dúvidas eu vou perguntando nesse mesmo tópico):

 

Eu assisto vários vídeos da imasters (hangouts) e também outros vídeos e sempre vejo eles falando de: Horizontal e Vertical.

 

  1. O que seria isso?
  2. Porque a classificação horizontal e vertical?
  3. Em qual momento é aplicado?
  4. Porque existem Frameworks classificados dessa maneira (Horizontal e Vertical)?
  5. Porque a Orientação a Objetos é horizontal?

 

Talvez uma pergunta resposda as outras, mas como são essas as dúvidas da mente, que venham as respostas.

 

Obrigado antecipadamente.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Abacate é uma fruta logo ela iria implementar Fruta correto?

O que eu posso fazer com uma fruta ? Comer ?:

interface Fruta{
    public function comer();
  }
 

 

Porque a Orientação a Objetos é horizontal?

Porque é assim que voce a programa, não se esqueça, classe não é objeto.

Compartilhar este post


Link para o post
Compartilhar em outros sites

O que eu posso fazer com uma fruta ? Comer ?:

 

Quem come é a pessoa e não a fruta.

 

Porque é assim que voce a programa, não se esqueça, classe não é objeto.

 

Creio que não foi uma explicação muito válida. Continua a mesma coisa.

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

  1. O que seria isso?

 

Horizontal => composição, agregação, associação

Vertical => herança

 

 

  1. Porque a classificação horizontal e vertical?

 

Porque herança é hierarquia, que é vertical. Veja um exemplo:

Lugares
    EstadosUnidos -> estende Lugares
        NovaIorque -> estende EstadosUnidos
        Ohio -> estende EstadosUnidos
        Arkansas -> estende EstadosUnidos
    Brasil -> estende Lugares
        SaoPaulo -> estende Brasil
        RioDeJaneiro -> estende Brasil
        Parana -> estende Brasil

Já o relacionamento horizontal não é uma hierarquia. Veja um exemplo:

Database
UserStorage possui um Database
ProductsStorage possui um Database

 

 

 

  1. Em qual momento é aplicado?

 

Herança é do tipo "é um", portanto quando você diz que classe A estende classe B, você assume semanticamente que A é um B.

Herança é erroneamente utilizada. Você vê muito classe de usuário estendendo classe de banco de dados, o que é errado.

 

Há uma frase bem popular: "Prefer composition over inheritance".

cai exatamente neste ponto de reutilização através de herança, composição e traits.

 

 

 

  1. Porque existem Frameworks classificados dessa maneira (Horizontal e Vertical)?

 

Na verdade, não é bem assim. Frameworks usam arquitetura vertical geralmente para fazer inversão de controle, mas não há essa classificação. Podemos até falar que boa parte dos frameworks usam mais herança do que composição, mas não falar que um framework só usa um ou outro.

 

 

 

  1. Porque a Orientação a Objetos é horizontal?

 

Porque é orientação a objetos, não é orientação a hierarquia. O relacionamento de objetos é horizontal e o de tipos (herança) vertical.

 

Herança é apenas um recurso de boa parte das linguagens de programação que possuem suporte para OOP. Ela é útil e efetiva, se usada cautelosamente, mas não substitui a composição.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Perfeita a resposta @Enrico Pereira. Obrigado.

 

Nesse meio tempo sumido eu comecei a praticar e escrevi um código de exemplo.

 

Mas antes vamos as dúvidas:

  1. É preciso ter muito conhimento em Orientação a Objetos para aprender UML e sim, qual o nível de conhecimento?
  2. Estou com um projeto em mente, mas por mais que eu saiba programar, entenda de lógica, eu não tenho conhecimento sobre todos os assuntos, então pelo que eu percebi TDD é uma etapa muito importante em um projeto, principalmente se for Open Source. Então, qual seria o nível de conhecimento em Orientação a Objetos para aprender TDD?
  3. Por mais que a ideia das interfaces sejam diferentes das classes abstratas o uso delas podem confundir. De qual forma devo pensar antes de implementar o meu sistema a fim de escolher qual das duas utilizar (ou as duas)?

Vamos ao código que eu criei:

 

BasketInterface.php

<?php

interface BasketInterface
{

    public function setCapacity($capacity);
    
    public function setWeight($weight);
    
    public function getCapacity();
    
    public function getWeight();

}

 

FruitInterface.php

<?php

interface FruitInterface
{

    public function setName($name);

    public function setSize($size);

    public function setWeight($weight);

    public function getName();

    public function getSize();

    public function getWeight();

}

 

Banana.php

<?php

abstract class Banana implements FruitInterface
{

    private $name;

    private $size;

    private $weight;

    public function __construct($name, $size, $weight)
    {

        $this->name = $name;

        $this->size = $size;

        $this->weight = $weight;

    }

    public function setName($name)
    {

        $this->name = $name;

    }

    public function setSize($size)
    {

        $this->size = $size;

    }

    public function setWeight($weight)
    {

        $this->weight = $weight;

    }

    public function getName()
    {

        return $this->name;

    }

    public function getSize()
    {

        return $this->size;

    }

    function getWeight()
    {

        return $this->weight;

    }

}

 

BasketOfFruit.php

<?php

class BasketOfFruit implements BasketInterface
{

    private $fruits = array();
    
    private $capacity;
    
    private $weight;

    public function __construct($capacity, $weight)
    {

        $this->capacity = $capacity;

        $this->weight = $weight;

    }

    public function addFruit(FruitInterface $fruit, $id)
    {

        if(count($this->fruits) < $this->capacity)
        {

            $this->fruits[$id] = $fruit;

            $this->weight += $fruit->getWeight();

        }

    }

    public function removeFruit($id)
    {

        if($this->hasFruit($id))
        {

            $this->weight -= $this->fruits[$id]->getWeight();

            unset($this->fruits[$id]);

        }

    }

    public function removeAllFruits()
    {

        foreach($this->fruits as $id => $fruit)
        {

            $this->weight -= $fruit->getWeight();

        }

        unset($this->fruits);

    }

    public function setCapacity($capacity)
    {

        $this->capacity = $capacity;

    }
    
    public function setWeight($weight)
    {

        $this->weight = $weight;

    }

    public function getCapacity()
    {

        return $this->capacity;

    }

    public function getWeight()
    {

        return $this->weight;

    }

    public function getFruit($id)
    {

        if($this->hasFruit($id))
        {

            return $this->fruits[$id];

        }

    }

    public function getAllFruits()
    {

        return $this->fruits;

    }

    public function hasFruit($id)
    {

        if(isset($this->fruits[$id]))
        {

            return true;

        }

        return false;

    }

}

 

BananaPlantain.php

<?php

class BananaPlantain extends Banana
{

}

 

index.php

<?php

require_once "BasketInterface.php";

require_once "FruitInterface.php";

require_once "Banana.php";

require_once "BasketOfFruit.php";

require_once "BananaPlantain.php";

# Cria a cesta de frutas com a capacidade de 3 frutas e com 2 de peso
$BasketOfFruit = new BasketOfFruit(3, 2);

# Pega o peso da cesta
var_dump($BasketOfFruit->getWeight());

# adiciona 3 bananas da terra na cesta, cada uma com um tamanho, peso e id.
$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "36 cm", 2.2), 1);

$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "37 cm", 1.4), 2);

$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "34 cm", 1.5), 3);

# Pega o peso da cesta
var_dump($BasketOfFruit->getWeight());

# Pega todas as frutas da cesta
print_r($BasketOfFruit->getAllFruits());

# Tenta adicionar mais uma fruta na cesta.
$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "38 cm", 2.5), 4);

# Pega todas as frutas da cesta
print_r($BasketOfFruit->getAllFruits());

# Remove a fruta com o id 2
$BasketOfFruit->removeFruit(2);

# Pega o peso da cesta
var_dump($BasketOfFruit->getWeight());

# Pega todas as frutas da cesta
print_r($BasketOfFruit->getAllFruits());

# Verifica se a fruta com id 2 ainda existe
var_dump($BasketOfFruit->hasFruit(2));

# Remove todas as frutas da cesta
$BasketOfFruit->removeAllFruits();

# Pega o peso da cesta
var_dump($BasketOfFruit->getWeight());

 

Tem algo errado ou eu fiz da forma correta? Lembrando que é um código simples.

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

  1. É preciso ter muito conhimento em Orientação a Objetos para aprender UML e sim, qual o nível de conhecimento?

 

Não. UML não é somente diagrama de classes. Há diagrama de sequência, diagrama de caso de uso, etc.

 

Na prática, diagramas de classes são os que menos são usados, principalmente quando você já tem um pouco de noção de como fazer as coisas, porque aí você não vai criar diagramas inúteis para perder tempo.

 

UML é uma linguagem universal de modelagem, sem o propósito de ser uma linguagem apenas para modelar pacotes/classes.

 

A principal utilidade de UML é documentação, seja de um pacote, de um padrão, de um conceito, de um fluxograma, de uma regra de negócio, etc.

 

 

 

  1. Estou com um projeto em mente, mas por mais que eu saiba programar, entenda de lógica, eu não tenho conhecimento sobre todos os assuntos, então pelo que eu percebi TDD é uma etapa muito importante em um projeto, principalmente se for Open Source. Então, qual seria o nível de conhecimento em Orientação a Objetos para aprender TDD?

 

TDD pode ser aplicado em qualquer tipo de código, não somente em códigos orientados a objetos.

 

TDD é uma metodologia constituída de três passos contínuos (red-green-blue):

-> Criar um teste -> rodar esse teste e vê-lo falhar

-> criar o mínimo de código possível para que o teste criado passe -> rodar o teste e vê-lo passar

-> refatorar

 

Ou seja, você não precisa ter um conhecimento avançado em OO para aprender TDD. Aliás, você acabou de aprender o conceito de TDD (estou falando sério). Para para testes unitários agora :)

 

 

 

  1. Por mais que a ideia das interfaces sejam diferentes das classes abstratas o uso delas podem confundir. De qual forma devo pensar antes de implementar o meu sistema a fim de escolher qual das duas utilizar (ou as duas)?

 

Há uma regra para um caso: você quer apenas um contrato -> use uma interface.

Não crie uma classe abstrata sem fim de ter comportamento nem crie uma classe abstrata quando você não precisa (Keep it simple, stupid!).

 

Quando você quer também comportamento, é sua escolha. Eu, na maioria dos casos, mantenho a interface a fim de evitar um acoplamento. Mas não há regra nesse caso.

 

----

 

 

 

    public function hasFruit($id)
    {

        if(isset($this->fruits[$id]))
        {

            return true;

        }

        return false;

    }

 

Você não precisa usar esse if, já que só quer o retorno do isset:

 

    public function hasFruit($id)
    {
        return isset($this->fruits[$id]);
    }

 

 


abstract class Banana implements FruitInterface

 

Hã? Você não precisa ter banana como abstrata, afinal banana já é uma fruta concreta. Mesmo que você tenha uma banana-da-terra, uma banana já é uma fruta. Portanto, deixe-a como classe concreta.

 

 

 

<?php

require_once "BasketInterface.php";

require_once "FruitInterface.php";

require_once "Banana.php";

require_once "BasketOfFruit.php";

require_once "BananaPlantain.php";

 

Use autoloading.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Estou tentando entender porque sempre mudam os meus títulos do fórum - Se eu não me engano esse era Explicações Orientação a Objetos, mudaram e colocaram Explicações. :ermm:

 

@Enrico Pereira

 

Não. UML não é somente diagrama de classes. Há diagrama de sequência, diagrama de caso de uso, etc.

 

Na prática, diagramas de classes são os que menos são usados, principalmente quando você já tem um pouco de noção de como fazer as coisas, porque aí você não vai criar diagramas inúteis para perder tempo.

 

UML é uma linguagem universal de modelagem, sem o propósito de ser uma linguagem apenas para modelar pacotes/classes.

 

A principal utilidade de UML é documentação, seja de um pacote, de um padrão, de um conceito, de um fluxograma, de uma regra de negócio, etc.

 

Realmente. :grin:

 

 

TDD pode ser aplicado em qualquer tipo de código, não somente em códigos orientados a objetos.

 

TDD é uma metodologia constituída de três passos contínuos (red-green-blue):

-> Criar um teste -> rodar esse teste e vê-lo falhar

-> criar o mínimo de código possível para que o teste criado passe -> rodar o teste e vê-lo passar

-> refatorar

 

Ou seja, você não precisa ter um conhecimento avançado em OO para aprender TDD. Aliás, você acabou de aprender o conceito de TDD (estou falando sério). Para para testes unitários agora

 

Obrigado. - Acho que já está na hora de parar para entender como funciona, afinal, preciso de meus códigos lindamente lindos. :grin:

 

Há uma regra para um caso: você quer apenas um contrato -> use uma interface.

Não crie uma classe abstrata sem fim de ter comportamento nem crie uma classe abstrata quando você não precisa (Keep it simple, stupid!).

 

Quando você quer também comportamento, é sua escolha. Eu, na maioria dos casos, mantenho a interface a fim de evitar um acoplamento. Mas não há regra nesse caso.

 

Quando eu criei o código eu não tinha assistido o hangout sobre OO aqui da Imasters.

Depois que eu verifiquei sua resposta eu indentifiquei muito com o que eles falaram e agora eu compreendo mais ou menos como funciona. - O que devemos fazer é perguntar: Isso é isso? Se for, é generalização (extensão). Como no caso da Banana e Banana da Terra. Banana da Terra é uma Banana.

 

Você não precisa usar esse if, já que só quer o retorno do isset:

 

Cara, isso foi uma merda que eu "fiz por fazer" na velocidade da luz para postar aqui e tentar tirar minha dúvida. - Tem nem explicação, realmente foi uma caca. :ermm:

 

Let's go to the refactored code:

 

Autoloader.php

<?php

class Autoloader
{

    public function __construct()
    {

        spl_autoload_register(array($this, "autoloadClass"));

        spl_autoload_register(array($this, "autoloadInterface"));

    }

    public function autoloadClass($filename)
    {

        spl_autoload($filename);

    }

    public function autoloadInterface($filename)
    {

        require_once $filename . "Interface.php";

    }

}

 

Banana.php

<?php

class Banana implements Fruit
{

    private $name;

    private $size;

    private $weight;

    public function __construct($name, $size, $weight)
    {

        $this->name = $name;

        $this->size = $size;

        $this->weight = $weight;

    }

    public function setName($name)
    {

        $this->name = $name;

    }

    public function setSize($size)
    {

        $this->size = $size;

    }

    public function setWeight($weight)
    {

        $this->weight = $weight;

    }

    public function getName()
    {

        return $this->name;

    }

    public function getSize()
    {

        return $this->size;

    }

    function getWeight()
    {

        return $this->weight;

    }

}

 

BananaPlantain.php

<?php

class BananaPlantain extends Banana
{

}

 

BasketInterface.php

<?php

interface Basket
{

    public function setDefinition($definition);

    public function setCapacity($capacity);
    
    public function setWeight($weight);

    public function getDefinition();
    
    public function getCapacity();
    
    public function getWeight();

}

 

BasketOfFruit.php

<?php

class BasketOfFruit implements Basket
{

    private $definition;

    private $capacity;
    
    private $weight;

    private $fruits = array();

    public function __construct($definition, $capacity, $weight)
    {

        $this->definition = $definition;

        $this->capacity = $capacity;

        $this->weight = $weight;

    }

    public function addFruit(Fruit $fruit, $id)
    {

        if(count($this->fruits) < $this->capacity)
        {

            $this->fruits[$id] = $fruit;

            $this->weight += $fruit->getWeight();

        }

    }

    public function removeFruit($id)
    {

        if($this->hasFruit($id))
        {

            $this->weight -= $this->fruits[$id]->getWeight();

            unset($this->fruits[$id]);

        }

    }

    public function removeAllFruits()
    {

        foreach($this->fruits as $id => $fruit)
        {

            $this->weight -= $fruit->getWeight();

        }

        unset($this->fruits);

    }

    public function setDefinition($definition)
    {

        $this->definition = $definition;

    }

    public function setCapacity($capacity)
    {

        $this->capacity = $capacity;

    }
    
    public function setWeight($weight)
    {

        $this->weight = $weight;

    }

    public function getDefinition()
    {

        return $this->definition;

    }

    public function getCapacity()
    {

        return $this->capacity;

    }

    public function getWeight()
    {

        return $this->weight;

    }

    public function getFruit($id)
    {

        if($this->hasFruit($id))
        {

            return $this->fruits[$id];

        }

    }

    public function getAllFruits()
    {

        return $this->fruits;

    }

    public function hasFruit($id)
    {

        return isset($this->fruits[$id]);

    }

}

 

FruitInterface.php

<?php

interface Fruit
{

    public function setName($name);

    public function setSize($size);

    public function setWeight($weight);

    public function getName();

    public function getSize();

    public function getWeight();

}

 

index.php

<?php

header("Content-Type: text/html; charset=utf-8");

require_once "Autoloader.php";

$autoloader = new Autoloader();

$BasketOfFruit = new BasketOfFruit("Cesta de Frutas", 3, 2);

echo "A " . strtolower($BasketOfFruit->getDefinition()) . " tem " . $BasketOfFruit->getWeight() . "kg com capacidade para " . $BasketOfFruit->getCapacity() . " frutas.<br>";

$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "36 cm", 2.2), 1);

$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "37 cm", 1.4), 2);

$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "34 cm", 1.5), 3);

echo "Foram adicionadas " . count($BasketOfFruit->getAllFruits()) . " frutas na cesta.<br>";

echo "A " . strtolower($BasketOfFruit->getDefinition()) . " agora tem " . $BasketOfFruit->getWeight() . "kg.<br>";

echo "Frutas da cesta:<br>";

foreach ($BasketOfFruit->getAllFruits() as $fruit) {

    echo "A fruta " . strtolower($fruit->getName()) . " tem " . $fruit->getWeight() . "kg.<br>";

}

echo "Adicionando mais uma fruta para a cesta.<br>";;

$BasketOfFruit->addFruit(new BananaPlantain("Banana da Terra", "38 cm", 2.5), 4);

if ($BasketOfFruit->hasFruit(4)) {

    echo "Fruta adicionada na cesta.<br>";

} else {

    echo "Não foi possível adicionar a fruta. A capacidade da cesta excedida.<br>";

}

echo "Removendo a fruta com " . $BasketOfFruit->getFruit(2)->getWeight() . "kg<br>";

$BasketOfFruit->removeFruit(2);

echo "A " . strtolower($BasketOfFruit->getDefinition()) . " agora tem " . $BasketOfFruit->getWeight() . "kg.<br>";

echo "Frutas da cesta:<br>";

foreach ($BasketOfFruit->getAllFruits() as $fruit) {

    echo "A fruta " . strtolower($fruit->getName()) . " tem " . $fruit->getWeight() . "kg.<br>";

}

echo "Removendo todas as frutas.<br>";

$BasketOfFruit->removeAllFruits();

echo "A " . strtolower($BasketOfFruit->getDefinition()) . " agora tem " . $BasketOfFruit->getWeight() . "kg.<br>";

Output

 

A cesta de frutas tem 2kg com capacidade para 3 frutas.
Foram adicionadas 3 frutas na cesta.
A cesta de frutas agora tem 7.1kg.
Frutas da cesta:
A fruta banana da terra tem 2.2kg.
A fruta banana da terra tem 1.4kg.
A fruta banana da terra tem 1.5kg.
Adicionando mais uma fruta para a cesta.
Não foi possível adicionar a fruta. A capacidade da cesta excedida.
Removendo a fruta com 1.4kg
A cesta de frutas agora tem 5.7kg.
Frutas da cesta:
A fruta banana da terra tem 2.2kg.
A fruta banana da terra tem 1.5kg.
Removendo todas as frutas.
A cesta de frutas agora tem 2kg.

 

Próxima etapa agora é estudar TDD e tentar melhorar esse código (fiz um macarrão na index.php), adicionar mais classes para tratar de várias coisas da vida real. Nada melhor do que aprender praticando.

 

Obrigado e qualquer dúvida postarei novamente.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tá loco, o Enrico não deixou ninguém mais responder :lol:

 

Mas tudo bem, ele manja mais. :P

 

Vou simplesmente deixar suas perguntas de TDD de lado porque TDD entra no meu cérebro e fica mais deslocado que um estudante africano numa escola japonesa então se eu pensar em responder alguma coisa vai estar errado. :yay:

 

Mas duas coisas que eu notei nesses seus códigos é que você está vendo interface como a cura da AIDS. Não é bem assim.

 

Herança vertical não é uma coisa ruim, basta apenas que seja aplicada corretamente.

 

Já foi dito que herança representa é um, agora uma coisa que aprendi sobre interfaces é que, para elas considera-se o pode ser um.

 

Eu quero chegar na sua Cesta de Frutas. Ela é uma cesta ou ela pode ser uma cesta?

 

Eu sei, eu sei, brasileiro usa até pote de sorvete vazio pra pôr fruta, mas vamos nos ater ao conceito.

 

Se uma Cesatde Frutas é, na sua essência, uma cesta, então temos sim uma herança:

 

 

abstract class AbstractBasket {}
 
class FruitsBasket extends Basket {}

 

A super-classe AbstractBasket será a responsável por manipular a cesta em si (adicionar, remover, contar...) e ela operará com objetos quaisquer.

 

Defini ela como abstrata porque mesmo uma cesta não específica, programaticamente falando, ela não deveria ser utilizada justamente porque um contêiner é um contêiner de alguma coisa.

 

Mesmo que essa cesta aceite qualquer coisa, você deve, na minha opinião, respeitar tal exigência.

 

À esse tipo de centário de Collections costuma-se ter um método abstrato comumente chamado de accept() que é invocado na antes da inclusão de um novo item ao array da coleção.

 

E para você limitar que uma cesta de frutas só aceite frutas, você implementa esse método abstrato e define que só Frutas são aceitas. E aí sim. Se um objeto pode ser uma Fruta, ele implementa uma interface

 

Muito texto, pouco código. O que eu disse aí cima resume-se, basicamente a isso:

 

 

abstract class AbstractBasket {
 
    protected $basket = array();
 
    public function add( $element ) {
 
        if( $this -> accept( $element ) ) {
 
            $this -> basket[] =& $element;
        }
 
        return $this;
    }
 
    abstract protected function accept( $element );
}
 
class FruitsBasket extends AbstractBasket {
 
    // Abstract method Implementation
 
    protected function accept( $element ) {
 
        if( ! $element instanceof Fruit ) {
 
            throw new InvalidArgumentException( 'Only fruits are accepted in this basket' );
        }
 
        return TRUE;
    }
}
 
 interface Fruits {}

 

Eu prefifo fazer essa cehcagem com um IF do que com um try...catch() porque acho mais legível, embora o try...catch() seja mesmo o mais apropriado.

 

Ufa!

 

A segunda coisa que eu ia dizer, que é tão mais simples que deveria ter sido dita em primeiro lugar, é quanto ao seu método removeAllFruits(). Ao final dele você está destruindo a propriedade e você não deve se acostumar a fazer isso.

 

Hoje o PHP permite que você manipule uma propriedade não definida criando-a em runtime. Mas e amanhã ou depois? Se alguma coisa puder adicionar uma fruta depois de todas terem sido removidas, pelo fato de a propriedade não existir mais, vai estragar tudo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Eu estou achando esse tópico simplesmente fantástico. Acho que qualquer iniciante em Orientação a Objetos tem dúvidas desse tipo, então nada melhor do que uma série de perguntas respondidas por pessoas que tem um bom coração, que se importam em ajudar o próximo e que já passaram por toda essa situação de aprendizado para nos ajudar.

 

Quero agradecer a todos e que continue ajudando as pessoas, porque vocês ganharam com isso, de uma forma direta ou indireta.

 

@offtopic

 

Por favor, @Bruno Augusto, você como moderador poderia alterar o título do tópico, deixar ele mais definido? - "Explicações... de?" - Poderia alterar para algo em relação a o tópico como: "Orientação a Objetos - Perguntas e Respostas" ou "Explicações - Orientação a Objetos" ou algum outro.

 

@topic

Tá loco, o Enrico não deixou ninguém mais responder :lol:

 

Mas tudo bem, ele manja mais. :P

Realmente, manja muito.

Mas duas coisas que eu notei nesses seus códigos é que você está vendo interface como a cura da AIDS. Não é bem assim.

Vou te explicar o que acontece.

Quando a gente está iniciando na orientação a objetos, por mais que você tenha entendido algum assunto, como a questão das interfaces, classes abstratas, associação, composição, agregação e afins, você sempre fica com alguma dúvida, e grande parte dessas dúvidas quando você passa a utilizar na prática. Teoria de certo ponto é fácil de entender, mas na hora da aplicação, quando tentamos aplicar o conceito em um problema próprio é muito diferente.

Herança vertical não é uma coisa ruim, basta apenas que seja aplicada corretamente.

Realmente, tenho conhecimento disso. Isso é muito lógico, é com você falou, o Enrico Pereira e eu também postei. Devemos pensar em herença quando perguntamos: "isso é isso"? Pois o conceito de herança se baseia nisso: "É um". Correto?

 

Até ai tudo bem, mas vamos lá.

 

Interface são um tipo, além de serem um contrato com métodos abstratos.

Classes abstratas também é um tipo, mas é também uma generalização de um modo mais rígido.

 

Pensando assim, os dois são "iguais", mas são utilizados de formas diferentes em casos diferentes.

 

O que aconteceu comigo foi: Como interface é um tipo, logo Basket(Cesta) é um tipo, correto? Logo definiria uma interface.

 

Uma Cesta de Frutas poderia ser uma definição ou nome, para uma cesta, logo Cesta de Frutas é uma Cesta (é um, mas também é um tipo)

 

Eu pensei dessa forma, por isso eu declarei uma interface para Basket com comportamentos comuns para todas as cestas que são: Tamanho, capacidade e definição (nome).

 

E quando eu criasse uma classe BasketOfFruits (Cesta de Frutas) eu implementaria Basket, porque Cesta de Frutas é uma Cesta, logo também é um tipo.

 

Mas depois que eu percebi o seguinte, a diferença (eu creio), de interface para classes abstratas entra nesse conceito. Quando eu declaro uma interface eu estou falando que todas as classes que implementa esse tipo herdam comportamentos comuns, mas que podem ser tratados de formas diferentes. Já em classes abstratas eu estou falando que se Cesta de Frutas É UMA Cesta, logo ela tem que se comportar como uma cesta, utilizando métodos como Add, pois todas as cestas elas colocaram algo, algo essa que eu não sei e nem quero saber a princípio, então, para não ter repetiçao de código, para cada cesta eu não ter que repetir o código um código comum entre Cestas, eu declaro métodos comuns que trabalhama de uma forma generalizada para todas as classes que vão herdar dela.

 

Estou correto?

 

O seu código só me fez cravar ainda mais essa ideia e passar a compreender a questão das interfaces e classes abstratas.

 

Eu acabei de assistir o hangout de Code Reuse, e foi simplesmente fantástico, me ajudou muito mais. - Mas vamos as dúvidas.

 

O João citou um caso de "herança múltipla", onde João é uma pessoa, mas ele também é louco e cabeludo, mas o PHP não suporta herança múltipla, sem falar que nesse caso seria errado ter herança múltipla, afinal, cada um se comporta de uma forma. Logo entramos em Traits.

 

Eu entendi a definição das Traits e em quais momentos podemos utilizar ela pelo Hangout, mas me restou uma dúvida:

 

- Podemos dizer que as Traits vieram para substituir a Herança Múltipla de uma forma melhorada?

 

Os traits são: comporta-se como, diferente das interfaces que é pode ser uma (onde pode ser algo, mas pode se comportar diferente), e temos as classes abstratas que: é uma.

 

A segunda pergunta é: Os traits não nos passa uma confiança, para isso precisamos declarar uma interface para termos a segurança de que o método que reutiliza o código de uma Trait ele DEVE ter o método por causa do contrato.

 

- O PHP deveria implementar um Trait SomeTrait implements SomeInterface {}?

 

Se isso já existir, me perdoem, não percebi, mas se não existir, qual o seu ponto de vista?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Devemos pensar em herença quando perguntamos: "isso é isso"? Pois o conceito de herança se baseia nisso: "É um". Correto?

 

Sim, podemos provar isso em código:

class Serializer {}
class JsonSerializer extends Serializer {}
class XmlSerializer extends Serializer {}
class Mysql {}

class Response {
    public function __construct(Serializer $s) {}
}

new Response(new Serializer()); // beleza, Serializer é um Serializer
new Response(new JsonSerializer()); // beleza, JsonSerializer é um Serializer
new Response(new XmlSerializer()); // beleza, XmlSerializer é um Serializer
new Response(new Database()); // vish, Database não é um Serializer, dará erro

 

 

 

O que aconteceu comigo foi: Como interface é um tipo, logo Basket(Cesta) é um tipo, correto? Logo definiria uma interface.

 

Qualquer interface, classe (normal, abstrata ou final) é um tipo.

 

 

Mas depois que eu percebi o seguinte, a diferença (eu creio), de interface para classes abstratas entra nesse conceito. Quando eu declaro uma interface eu estou falando que todas as classes que implementa esse tipo herdam comportamentos comuns, mas que podem ser tratados de formas diferentes. Já em classes abstratas eu estou falando que se Cesta de Frutas É UMA Cesta, logo ela tem que se comportar como uma cesta, utilizando métodos como Add, pois todas as cestas elas colocaram algo, algo essa que eu não sei e nem quero saber a princípio, então, para não ter repetiçao de código, para cada cesta eu não ter que repetir o código um código comum entre Cestas, eu declaro métodos comuns que trabalhama de uma forma generalizada para todas as classes que vão herdar dela.

 

Um pouco estranho o modo de falar assim, o pensamento em geral está correto, mas a definição não.

 

Quando você implementa uma interface, você também faz o tipo "é um". Porém você não herda NENHUM comportamento, apenas é obrigado a cumprir (implementar) os métodos contidos na interface para cumprir o contrato.

 

Em ambas você fala que "x é y", tanto em classes quanto em interfaces.

 

 

O João citou um caso de "herança múltipla", onde João é uma pessoa, mas ele também é louco e cabeludo, mas o PHP não suporta herança múltipla, sem falar que nesse caso seria errado ter herança múltipla, afinal, cada um se comporta de uma forma. Logo entramos em Traits.

 

Na-na-nina-não. Traits, diferentemente de classes e interfaces, NÃO são um tipo. Traits apenas inserem comportamento de forma encapsulada, é quase um ctrl-c + ctrl-v feito pela linguagem.

 

 

- Podemos dizer que as Traits vieram para substituir a Herança Múltipla de uma forma melhorada?

 

Não. Traits NÃO são herança.

 

 

A segunda pergunta é: Os traits não nos passa uma confiança, para isso precisamos declarar uma interface para termos a segurança de que o método que reutiliza o código de uma Trait ele DEVE ter o método por causa do contrato.

 

- O PHP deveria implementar um Trait SomeTrait implements SomeInterface {}?

 

Uma trait não pode implementar uma interface, pois traits não atribuem tipos, apenas propriedades/métodos.

 

A questão de haver uma interface com a implementação da trait é para fazer type hinting. Isso não é obrigatório.

 

Traits não são necessárias. Elas são recursos adicionais da linguagem e uma feature com grande potencial de abuso, infelizmente. Mas elas não são obrigatoriamente ruins. Eu, particularmente, não gosto delas e não uso. Composição FTW.

 

Há material na internet discutindo isso:

http://phpmaster.com/using-traits-in-php-5-4/

http://stackoverflow.com/questions/7892749/traits-in-php-any-real-world-examples-best-practices

http://blog.ircmaxell.com/2011/07/are-traits-new-eval.html

Compartilhar este post


Link para o post
Compartilhar em outros sites

O problema de classes abstratas serem tratadas como tipos é sofre com Syntatic Sugar que, a grosso modo, seria fazer classes abstratas não abstraírem quase nada ou abstraindo as coisas erradas.

 

No estado atual dos meus códigos (que eu larguei mão por um tempo de birra) ainda sofro um pouco com isso, mas bem menos que no passado depois que o Evandro Oliveira puxou minha orelha.

 

Aproveitando que eu não caí de sono no teclado ainda, vou editar o tópico

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Enrico Pereira

Qualquer interface, classe (normal, abstrata ou final) é um tipo.


Justamente, não neguei e compreendo isso. Você me entendeu errado. Agora eu compreendo quando utilizar interface ou classes abstratadas, mas antes o que me deixava intrigado é isso. Se classes e interfaces são um tipo, em qual diabos de hora usar elas? (pensava assim).

Mas depois as coisas foram ficando claras. - E eu tentei explicar mais ou menos, mas você complementou o que eu falei.

Como eu sou o iniciante aqui, vou tentar explicar o que eu entendi até agora para que os que virão a aprender também possam entender pelo meu ponto de vista e se indentificar (talvez).

Vamos a um exemplo:

abstract class Pessoa { abstract public function falar(); }
interface Pessoa { public function falar(); }

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.

Exemplo:

As classes abstratas também podem ser consideradas generalização. Logo quem extende ela herdará não só os métodos, mas comportamentos. - Então "falar" seria algo generalizado. Estamos falando que TODO mundo fala igual (ISSO É ERRADO, NINGUÉM FALA IGUAL).

abstract class Pessoa {
    public function falar($mensagem) { echo $mensagem; }
}

Mesmo que você possa extender 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".

Nesse caso entra as interfaces:

interface Pessoa {
    public function falar($mensagem);
}

Dessa forma, quem herda ou "é uma" pessoa, provavelmente fala. Logo temos a confiança de que TODAS as pessoas falam.

E quando utilizar classes abstratas é realmente a questão da "generalização de um modo mais rígido" pois eu falo que TODOS fazem algo igual ou tem comportamentos iguais.

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.

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.

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.

@Bruno Augusto

O problema de classes abstratas serem tratadas como tipos é sofre com Syntatic Sugar que, a grosso modo, seria fazer classes abstratas não abstraírem quase nada ou abstraindo as coisas erradas.


Bom ponto de vista.

Aproveitando que eu não caí de sono no teclado ainda, vou editar o tópico


Muito obrigado!

Vamos para a pergunta? :skull: .

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?

Obrigado :graduated:

Compartilhar este post


Link para o post
Compartilhar em outros sites

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".

Voce tem certeza sim uai, o metodo é publico...

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.