Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Ola pessoal
Estou estudando object calisthenics, e tive algumas dúvidas, sobre:
1) Encapsule todos os tipos primitivos e Strings, mas caso ele tenha comportamento.
O que é uma variável que contem tipo primitivo possui um comportamento?
2) Use coleções de primeiro nível.
Qualquer classe que contenha uma coleção, não deve conter outras propriedades
Então a classe coleção teria somente uma única propriedade?
Ou essa regra diz que a classe coleção pode conter sim outras propriedades, porem que uma dessas propriedades, seja somente exclusiva para guardar as instâncias, que no caso seria as coleções. Correto? Somente uma propriedade teria o privilégio de guardar as coleções.
Exemplo:
class Itens extends Iterator
{
private $itens = [];
public function add(Item $item)
{
// do add
}
public function filter(array $filter)
{
// do filter
}
public function merge(Itens $itens)
{
// do merge
}
}
No exemplo acima, see.. caso a classe Itens precisa-se de mais uma outra qualquer propriedade alem da $items, seria um erro fazer isso? pois só pode conter 1 propriedade
3) Um ÚNICO operador de objeto por linha
Vários níveis de instâncias estão sendo acessado e é isso que deve ser evitado. Correto?
$this->manager->getConfig()->getSegment()->setName("foo");
Neste próximo exemplo, somente um nível sendo acessado. O correto a se fazer.
$filterChain
->addFilter(new Zend_Filter_Alpha())
->addFilter(new Zend_Filter_StringToLower);
Então se for usar interface fluente, sempre usar o mesmo nome de método da instância? E evitar acessar vários níveis de instancias?
4) Sem getters / setters / propriedades
Isso que dizer que devemos evitar getters e setters, sempre que possível??
Li artigos onde falava que getters e setters são perigosos, e devem ser evitados e já outros artigos incentivando o uso.. então fiquei na dúvida dessa regra
Desde já agradeço
É importante lembrar que Object Calisthenics são recomendações. Alguns poucos afetam a performance (else e o principal).
O que é uma variável que contem tipo primitivo possui um comportamento?Esse "mas" é que está estranho. Mas em linhas gerais, deve encapsular tudo para prevenir o Anti-Pattern Primitive Object.
O comportamento, dito ai, é voltado para usos que, por exemplo, um Integer não consegue expressar, por si só, o seu sentido ou não é tão bom quanto outro. Mas esse mesmo Integer, tem aplicações diferente, que é o caso do ValueObject.
Tanto horas quanto anos são integers, mas um não pode ser usado no lugar do outro. Se um método estiver pedindo uma entrada integer, o nome do método ou o nome do parâmetro deve especificar o que espera receber. Com a tipagem de uma classe, além do seu código possuir uma maior coesão, torna seu código mais fácil de ser lido.
Outro ponto são os ValueObjects, que pode ser visto no link acima ou no exemplo abaixo:
http://forum.imasters.com.br/topic/541651-entidade-x-value-object/
Como por exemplo, dinheiro é um float/double. Entretanto, não existe dinheiro negativo, você apenas pode creditar ou debitar uma quantia positiva de um valor. Logo, toda a classe que necessitar de um valor monetário, terá de possuir uma validação para isso.
>
2) Use coleções de primeiro nível.
Qualquer classe que contenha uma coleção, não deve conter outras propriedades
Então a classe coleção teria somente uma única propriedade?
Ou essa regra diz que a classe coleção pode conter sim outras propriedades, porem que uma dessas propriedades, seja somente exclusiva para guardar as instâncias, que no caso seria as coleções. Correto? Somente uma propriedade teria o privilégio de guardar as coleções.
Exemplo:
class Itens extends Iterator
{
No exemplo acima, see.. caso a classe Itens precisa-se de mais uma outra qualquer propriedade alem da $items, seria um erro fazer isso? pois só pode conter 1 propriedade
Na verdade, é uma regra de substituição para separar responsabilidades. Uma classe que possua uma lista, não deve implementar comportamentos dessa lista.
Como os comportamentos padrões de um Array não são reproduzidos de forma orientada à objetos, você pode usar uma classe genérica ou implementar a sua própria classe.
Entretanto, isso não é verdade para o PHP (mas é para C# e Java).
Por exemplo, no PHP, não existe um tipo de lista que é tipada, mas existe no Java e no C#. Você pode criar uma lista que permite apenas um tipo de objeto como parâmetro.
Pode ver um exemplo implementado no PHP aqui:
http://forum.imasters.com.br/topic/537066-tutorial-integridade-de-colecoes-com-uso-de-iterator/
>
3) Um ÚNICO operador de objeto por linha
Vários níveis de instâncias estão sendo acessado e é isso que deve ser evitado. Correto?
$this->manager->getConfig()->getSegment()->setName("foo");
Neste próximo exemplo, somente um nível sendo acessado. O correto a se fazer.
$filterChain
Então se for usar interface fluente, sempre usar o mesmo nome de método da instância? E evitar acessar vários níveis de instancias?
Essa definição, conhecida como Law of Demeter, é exemplificada, por Robert C. Martin, com Train Wrecks. É uma regra baseada no "knows too much" (sabe de mais). Se um classe precisa ir "tão a fundo" em um objeto, ele ou está sabendo demais, ou está recebendo mais do que o necessário. Ou até pode estar fazendo mais do que a sua responsabilidade.
O segundo exemplo é uma exceção pois não se trata de saber demais, é apenas o uso de fluent interface.
Não há muita o que explicar sobre essa regra, existem casos e casos. Normalmente, quando a lei de Demeter é violada, outras princípios também o são.
Isso que dizer que devemos evitar getters e setters, sempre que possível??Li artigos onde falava que getters e setters são perigosos, e devem ser evitados e já outros artigos incentivando o uso.. então fiquei na dúvida dessa regra
Desde já agradeço
Essa é outra interpretativa e relativa. Métodos get/setter devem ser usados para retornar/inserir algo. Entretanto, você deve dizer para que o objeto faça algo e não fazer perguntas sobre o seu estado para realizar as ações.
Nesse caso, é importante entender, também, sobre encapsulamento.
Veja abaixo, valores dispersos não fazem sentido algum:
As variáveis acima não possuem sentido algum sem nenhum contexto. Entretanto, encapsulando-as, entraremos em um contexto.
Class Rectangle
{
E agora, eu preciso calcular a área desse retângulo:
É nesse momento que mora o problema. As dimensões de um retângulo não fazem o menor sentido fora do seu contexto. Outro ponto, é a necessidade de um cálculo externo. O cálculo nada mais é que a representatividade da área e, nesse caso, ela não faz o menor sentido fora do retângulo.
Logo, essa situação pode ser revertida adicionando a responsabilidade sobre o cálculo ao retângulo e removendo a possibilidade de usar os valores de forma externa.
Class Rectangle
{
Dessa forma, agora, o cálculo da área é específico do retângulo (tal qual é de um triângulo, trapézio, etc..). Outra situação, que pode ser considerada, é o fato do retângulo poder ter seu estado alterado após a sua instância (o que, nesse caso, não é muito comum).
Assim, pode-se mudar o setters para o seu construtor:
Class Rectangle
{
E o seu uso:
Todo o processo, acima demonstrado, é conhecido como Tell, don't ask.
— Alec SharpA explicação do link abaixo é interessante também:
http://stackoverflow.com/questions/565095/are-getters-and-setters-poor-design-contradictory-advice-seen
Entretanto, cada caso deve ser considerado diferente. Não é porquê, nesse exemplo, foi feito dessa forma, que todos os outros serão.
No mais, object calisthenics foram criadas pela comunidade Java e portadas para o PHP. Em versões mais antigas do PHP, encapsular tipos primitivos era ruim, pois o PHP não gerenciava bem quando uma aplicação criava muitos objetos. Hoje em dia, isso é diferente.