Um objeto precisa representar uma entidade?
Por uma entidade que significa algo como um Product
, Motor
, um ParkingLot
etc, um físico, ou mesmo um objecto não-físico conceptual clara - algo que está bem definida, com alguns dados básicos pertencem claramente ao objecto, e algumas funções / métodos que operam claramente nos dados principais.
Por exemplo, eu posso ter um objeto de a Demon
, uma entidade em si, talvez imaginária e não física, mas uma entidade, no entanto
Um objeto pode ser apenas uma coleção de métodos , um conjunto comum de procedimentos vinculados a um objetivo comum?
Exemplo: uma classe pode ser chamada MotorOperations
ou MotorActions
, onde não há entidade, mas métodos dentro da classe fazem coisas como
- getMotorDataFromHTMLForm ()
- getMotorManufacturers ()
- selectMotorFromUserRequirements ($ requirements)
- canMotorCanHandleOperatingConditions ($ conditions)
- computePowerConsumptionForMotor ($ id)
Uma classe é normalmente definida como dados centrais do objeto + operações nos dados. Portanto, para um Motor
, pode haver algumas variáveis de motor relacionadas às especificações do motor e pode haver operações que combinam esses dados para produzir alguma coisa.
No meu caso, é mais como se eu tivesse uma classe com operações em dados + dados que são passados pela classe, não há dados centrados em "Operações Motoras", exceto dados temporários de passagem pela classe.
Pergunta, questão
As classes podem representar objetos sem entidade? Se não, por que eles são ruins / incompletos / não centrados no OOP? Existem maneiras pelas quais eles precisam ser alterados / aprimorados conceitualmente para estar alinhados com o POO?
MotorActions
ouMotorOperations
são boas idéias ou não.Respostas:
Não , um objeto não precisa representar uma entidade.
Na verdade, eu argumentaria que quando você para de pensar em objetos como entidades físicas é quando finalmente obtém os benefícios que o OOP promete.
Este não é o melhor exemplo, mas o design da Cafeteira é provavelmente o local onde a luz começou a acender para mim.
Objetos são sobre mensagens. Eles são sobre responsabilidades. Eles não são sobre carros, usuários ou pedidos.
Sei que ensinamos OO dessa maneira, mas depois de algumas tentativas, fica evidente como é fundamentalmente frustrante descobrir para onde as coisas vão quando você tenta fazer MVC, MVVM ou MVWhatever. Seus modelos ficam ridiculamente inchados ou seus controladores. Para a navegabilidade, é ótimo saber que tudo o que toca em Veículos está no arquivo Vehicle.ext, mas quando seu aplicativo é sobre Veículos, você inevitavelmente acaba com 3000 linhas de espaguete nesse arquivo.
Quando você tem uma nova mensagem para enviar, possui pelo menos um novo objeto e talvez um par deles. Portanto, na sua pergunta sobre um conjunto de métodos, eu argumentaria que você está potencialmente falando sobre um pacote de mensagens. E cada um pode ser seu próprio objeto, com seu próprio trabalho a fazer. E tudo bem. Ficará aparente à medida que você divide as coisas, que realmente precisam estar juntas. E você os junta. Mas você não coloca todos os métodos imediatamente em uma gaveta vagamente apropriada por conveniência, se quiser aproveitar o OO.
Vamos falar sobre bolsas de funções
Um objeto pode ser apenas uma coleção de métodos e ainda ser OO, mas minhas "regras" são bastante rígidas.
A coleção deve ter uma única responsabilidade, e essa responsabilidade não pode ser tão genérica quanto "Faz coisas para os motores". Posso fazer uma fachada de camada de serviço, mas tenho plena consciência de que estou sendo preguiçoso por motivos de navegabilidade / descoberta, não porque estou tentando escrever código OO.
Todos os métodos devem estar em uma camada consistente de abstração. Se um método recuperar objetos Motor e outro retornar Cavalos-força, isso provavelmente está muito distante.
O objeto deve funcionar no mesmo "tipo" de dados. Esse objeto faz coisas com os motores (liga / desliga), este faz coisas com comprimentos de manivela, este lida com o seqüenciamento de ignição, este assume um formato html. Esses dados poderiam ser campos no objeto e pareceriam coesos.
Geralmente construo objetos desse tipo quando estou fazendo transformações, composições ou simplesmente não quero me preocupar com mutabilidade.
Acho que focar nas responsabilidades dos objetos me leva à coesão. Tem que haver alguma coesão para ser um objeto, mas não precisa haver campos nem muito comportamento para que seja um objeto. Se eu estivesse construindo um sistema que precisasse desses 5 métodos motores, começaria com 5 objetos diferentes que fazem essas coisas. Quando encontrei elementos comuns, começava a mesclar as coisas ou usava objetos "auxiliares" comuns. Isso me leva a preocupações abertas / fechadas - como posso extrair esse pouco de funcionalidade para nunca precisar modificar esse arquivo específico novamente, mas ainda usá-lo quando necessário?
Objetos são sobre mensagens
Os campos pouco importam para um objeto - obter e definir registros não muda o mundo fora do programa. A colaboração com outros objetos realiza o trabalho. No entanto, a força do OO é que podemos criar abstrações para não precisar pensar em todos os detalhes individuais de uma só vez. Abstrações que vazam ou não fazem sentido são problemáticas, por isso pensamos profundamente (talvez demais) sobre a criação de objetos que correspondem aos nossos modelos mentais.
Pergunta-chave: Por que esses dois objetos precisam se comunicar?
Pense no objeto como um órgão em uma pessoa - ele tem um objetivo padrão e só muda de comportamento quando recebe uma mensagem específica com a qual se importa.
Imagine um cenário em que você está na faixa de pedestres e um carro está chegando rápido. Como objeto cerebral, detecto um estressor. Eu digo ao hipotálamo para enviar hormônio liberador de corticotrofina. A hipófise recebe essa mensagem e libera hormônio corticotrófico adrenal. As glândulas supra-renais recebem essa mensagem e criam adrenalina. Quando o objeto muscular recebe essa mensagem de adrenalina, ele se contrai. Quando o coração recebe a mesma mensagem, ele bate mais rápido. Há toda uma cadeia de jogadores envolvidos no início do comportamento complexo de correr do outro lado da rua e são as mensagens que importam. O objeto do cérebro sabe como fazer com que o hipotálamo envie o alerta, mas não conhece a cadeia de objetos que eventualmente fará o comportamento acontecer. Da mesma forma, o coração não tem ideia de onde vem a adrenalina,
Portanto, neste exemplo ( simplificado ), o objeto da glândula adrenal precisa apenas saber como tomar ACTH e produzir adrenalina. Ele não precisa de campos para fazer isso, mas ainda parece um objeto para mim.
Agora, se nosso aplicativo for projetado apenas para correr do outro lado da rua, talvez eu não precise da glândula pituitária e dos objetos da glândula adrenal. Ou preciso apenas de um objeto da hipófise que faça apenas uma pequena parte do que conceitualmente podemos ver como o "modelo da hipófise". Todos esses conceitos existem como entidades conceituais, mas é um software e podemos criar o AdrenalineSender ou MuscleContractor ou qualquer outra coisa e não nos preocupar muito com a "incompletude" do nosso modelo.
fonte
MotorOperations
ouMotorActions
". A partir disso, estou bastante confiante de que tanto os originais e projetos classe final do exemplo queda cafeteira na definição do OP de "representar uma entidade"Em resumo, você pode fazer qualquer coisa, mas esse cenário específico seria contrário aos princípios da OOP :)
O que você está descrevendo às vezes é chamado de classe "utilitário" - geralmente um sinal de cheiro de código. Você deseja evitar a criação de classes com o objetivo de manter alguns métodos juntos.
Nem todo objeto no seu aplicativo precisa estar vinculado a uma entidade da vida real, como um motor ou carro; esses são objetos de negócios. Em seu aplicativo, é provável que você use muitos de seus objetos de negócios, mas também precisará de mais segregação para outras operações que não fazem parte de entidades comerciais, como as listadas.
Você deve dar uma olhada nos padrões arquiteturais comuns - um deles é o MVC (Model-View-Controller) .
Se eu fosse distribuir os métodos listados usando o MVC, aqui está o que eu faria:
Ver classe:
Classe de modelo (motor essencial):
Classe de Controlador (MotorsController):
Parece que você está usando PHP; Uma boa estrutura MVC para se olhar é o Laravel . Em seus exemplos, eles ilustram bem a que métodos pertencem.
Outra fonte de informação mais genérica sobre como decidir aonde os métodos pertencem são os princípios GRASP e SOLID .
fonte
MotorOperations
paraMotorsController
e limpá-lo um pouco, minha coleção de funções será em linha com OOP?Utils
classe seria um exemplo de cheiro de código? Apenas curioso, já que eu gostei de ter funções util aleatórias agrupadas em umaUtils
classe em vez de apenas funções independentes ... na minha experiência, isso torna o código um pouco mais legível, mas minha experiência é limitada.Pode? Sim. Devemos? Provavelmente não - ou pelo menos não como você está expressando as coisas.
Na verdade, os objetos são melhores quando não representam um objeto físico diretamente, uma vez que a realidade é tão raramente mapeia bem o código. Mas eles precisam representar um conceito coeso ou objeto de código. Eles precisam representar uma única responsabilidade coesa.
Apenas agrupar várias funções tangencialmente relacionadas é um espaço para nome ou um módulo - não um objeto na linguagem OOP. Elas podem ser úteis, mas não são as mesmas, e exigem um tipo diferente de uso / pensamento para funcionar com eficácia.
fonte
bundling a bunch of tangentially related functions together is a namespace
: isso soa mais como paradigma processual do que orientado a objetos.Uma classe deve modelar algo - caso contrário, é inútil. No entanto, o que está sendo modelado pode não ser uma "coisa" física; em vez disso, pode ser uma representação de algo que não é 'real', mas que é necessário para controlar o sistema que está sendo modelado. Por exemplo, em um sistema de controle de semáforo, você poderia muito bem ter algum tipo de classe ControlSignal, representando um sinal enviado de uma parte do sistema para outra para indicar que alguma ação precisa ser executada. No "mundo real", esses sinais podem consistir em impulsos elétricos transmitidos pelos fios de uma caixa para outra. O processo de modelagem de algo que não é "real" como um objeto concreto é chamado de "reificação".
Boa sorte.
fonte
Não. (Título editado para fazer a pergunta oposta!)
por exemplo:
ou
No entanto, em geral, o ideal por trás da OOP é afastar-se da
para
fonte
Eu acho que visualizar algo no mundo real é útil ao codificar classes, mas não é necessário.
De fato, dependendo de como você quer ser literal, muitos objetos com os quais trabalhamos não têm representações físicas. Por exemplo - considere a arquitetura MVC. No mundo real, não há modelo ou controlador, mesmo que eles geralmente sejam representados por classes. Os três juntos geralmente representam algo, mas nem sempre - mas como eu disse, você provavelmente poderia forçar um encaixe em algo se você realmente quiser (e ser capaz de imaginar ALGO ajuda!) Visualizo a maioria dos objetos de alguma forma - apenas nada você veria no mundo real).
Na maioria das vezes, essas "Regras" que você aprenderá sobre OO são apenas diretrizes destinadas a orientá-lo a pensar em OO, não necessariamente em coisas com as quais você se preocupa muito depois de usá-lo para codificar diariamente.
A propósito, o OO em si não é uma panacéia e não ajuda muito em sua primeira passagem na codificação de alguma solução, mas acho que, se bem feito, é uma maneira verdadeiramente fantástica de organizar o código para que possa ser mais prontamente entendido mais tarde. Escrever código de manutenção é provavelmente uma das tarefas mais difíceis no desenvolvimento de software e, em muitos casos (qualquer coisa que exija depuração / manutenção contínua), é de longe a mais importante.
fonte
Pergunta: Qual entidade
Logger
representa?Não metaforicamente - literalmente.
Ao explicar o POO aos alunos, é útil explicar objetos com analogias com o mundo físico.
Alan Kay - um dos pais da OOP - escreveu o seguinte:
fonte
A partir disso, os objetos são melhor entendidos como
objetos autárquicos que encapsulam / ocultam dados
comunicação com outros objetos via mensagens
Definitivamente: pense em
Math
Em relação ao seu exemplo:
Para decidir onde colocar esses métodos, você deve dar uma olhada em
responsibilities
: quem é responsável por quê .O contexto desse método seria construir um objeto motor . Não é responsabilidade do motor criar-se a partir dos dados recuperados por meio de um formulário . Existem pelo menos dois objetos envolvidos; um é o motor e o outro é o criador do motor .
O contexto típico em que alguém escreveria esse método é a
service
.Isso também seria usado em um
service
contextoEsta é uma pergunta para um
motor
objetoEssa também é uma pergunta que deve ser feita ao próprio motor.
tl; dr
A metáfora de
objects
como objetos fisicamente é mais irritante do que útil.fonte
thing
dado com dados em que os dados claramente pertencem à coisa e funções que operam claramente nos dados que pertencem à coisa". Portanto, nesse caso, o Logger, embora não seja físico, é um conceito semelhante ao de um "diário de bordo físico". Se ele tem dados que é fundamental para seu estado, e não é apenas transitória a ele, que pode depender de aplicação e interpretação .. e é mais assim que a minha pergunta ia ..Sim, você pode fazer isso. Mas você está essencialmente criando uma classe para fornecer a mesma funcionalidade de uma biblioteca de procedimentos. O único motivo para fazer isso é se sua linguagem não possui módulos procedimentais (por exemplo, Java ou Ruby).
Em uma linguagem com módulos procedurais (acho que o PHP possui módulos procedurais), você pode considerar usar apenas um módulo procedural.
Você também pode redesenhar sua classe para que uma instância da classe represente um objeto coerente.
Mas use apenas a notação OO quando estiver fornecendo energia extra, não apenas por ser OO!
fonte
Nas palavras dos leigos
Tais classes existem, por exemplo, o Java SDK possui a classe Collections, que consiste exclusivamente em métodos estáticos que operam ou retornam coleções.
Portanto, a resposta seria não, nem todas as classes precisam ser modeladas a partir de uma entidade de domínio.
Por outro lado, essas classes são poucas ou devem ser poucas em um programa feito em uma linguagem OOP, uma vez que o poder real da OOP reside no polimorfismo e no encapsulamento.
Seria como usar um avião para ir de um lugar para outro, não voando, mas dirigindo-o pelas estradas. Os aviões têm rodas como os carros, mas pretendem voar.
fonte
Não, uma classe apenas representa algo que pode ser instanciado, tem membros e pode ser herdado.
De fato, seu idioma pode ter classes estáticas, que nem sequer são instanciadas mais de uma vez.
O .NET
Math
é um ótimo exemplo de uma classe "profissional" que não representa nenhuma entidade (a menos que você queira ser filosófico sobre o que é matemática ...) e também ilustra um caso de uso legítimo dessa classe. Possui apenas métodos e 2 campos (ambos representando constantes individuais).A hierarquia de classes de uma biblioteca semelhante
Math.Net
agrupa métodos matemáticos / numéricos em classes por tipo. Aqui, as classes representam não uma entidade, mas uma categoria lógica.Eu próprio frequentemente acabo criando classes (estáticas) que nada mais são do que um pacote de funções relacionadas (estáticas) ou um monte de constantes convenientemente agrupadas em um local central. Eu não diria que esse é um bom design, mas às vezes é a solução mais direta.
fonte
As respostas às suas perguntas dependem, em última análise, da precisão com que alguém define termos como "classe" e "entidade". Você fez um bom trabalho ao definir o último, permitindo entidades físicas e conceituais. Mas o termo "classe" para puristas sempre será "uma fábrica para instanciar objetos com uma representação interna específica" e, para pragmatistas, o termo abrangerá aquelas coisas em Java ou C ++ desprezadas pelos puristas. O mesmo vale para o termo "OOP", que os pragmáticos podem dizer que Java e C ++ fazem, mas quais puristas entenderiam o que Alan Kay quis dizer quando comentou ["Inventei o termo orientado a objetos e posso dizer que não tenha C ++ em mente "] ( Então, o que * Alan Kay realmente quis dizer com o termo" orientado a objetos "? ).
Se você adotar a visão pragmatista, poderá aceitar suas classes de utilitário sem instância. Mas a visão purista é mais interessante. OPA, de acordo com Kay, sempre foi mais sobre as mensagens do que sobre as aulas. Então, para suas perguntas:
Não. Classes classificam objetos. As classes são, por definição, aquelas entidades para as quais você envia uma mensagem, como
new
para produzir um objeto. Um objeto é uma entidade criada a partir de uma classe. Existem classes para fabricar, e realmente classificar, objetos. É isso que as aulas fazem. Classes criam objetos. Usamos classes para classificar objetos. Portanto, se C é apenas um conjunto de métodos que não permite instanciação ou subclasse, não pode haver objetos classificados por C, portanto, C não é uma classe.Eles não são ruins. Só não os chame de aulas. Um pacote de métodos é OOPable: algo para o qual você pode enviar uma mensagem para chamar um método, mas não é uma classe, a menos que possa instanciar um objeto. Você conhece Ruby? No Ruby, um módulo é um pacote de métodos. Uma classe é um módulo que pode instanciar objetos. Não há nada de ruim em um módulo . Mas o que diferencia uma classe de um módulo (em termos puros de OOP) é que uma classe pode ter instâncias. Um módulo é apenas alguns métodos. A confusão é que C ++, Java e outras linguagens usam o termo "classe" para classe e módulo .
Agora, para examinar um de seus exemplos específicos, você pergunta sobre uma
MotorOperations
classe para a qual você pode enviar a mensagemcomputePowerConsumptionForMotor
com argumentoid
. Isso é ruim? Pelo menos, não viola o princípio Tell Don't Ask . Temos que fazer uma aula de motor e enviar apowerConsumption
mensagem? Talvez não 100% do tempo, mas talvez tentar fazer isso levará a algumas informações interessantes sobre o seu código. Ou pode levar a uma explosão de turmas que seriam ruins.Se "fazer OOP" for importante para você, você precisará procurar maneiras de arquitetar um sistema em componentes que se comunicam enviando mensagens um para o outro. Isso é exatamente o que é POO , ou pelo menos o que o criador do termo tinha em mente. As classes de utilitário não são OOP nessa exibição. Mas para algumas pessoas, podem ser.
Tentar transformar todo um sistema amplo em milhões de objetos vivos, respiratórios, todos instanciados nas aulas, pode funcionar em alguns projetos. Mas se você estiver criando classes artificiais e com som errado, então os módulos devem ser introduzidos. Tente enfatizar as classes e use módulos quando as classes instáveis forem ridículas.
TL; DR - pacotes de métodos nem sempre são ruins. Tente usar classes instáveis primeiro. Retorne aos "módulos" somente quando necessário.
fonte
Tomando os exemplos dados:
Eles se parecem com métodos "de fábrica", que retornariam um
Motor
objeto. O segundo implica que você está criando um novo objeto para atender aos requisitos ou possui um banco de dados ou uma coleção de motores na memória que está examinando. Nesse caso, deve ser um método para isso. Ou poderia ser um método no objeto de requisitos.De onde você os está pegando? É para isso que deve ser um método.
Parece que eles devem ser métodos
Motor
.fonte
getMotorManufacturers
é retornar todos os fabricantes de motores do banco de dados. Não sei para onde isso vai. Ele vai me levar algum tempo para desvendar esse BOPUM para colocar as coisas onde eles precisam ir ..getMotorManufacturers
do banco de dados. O banco de dados não pode ter um método ... Atualmente, tenho um padrão DataMapper que consulta o banco de dados, inicializa uma matriz e a preenche com Objetos Motorizados (também contendo informações do Fabricante) e, em seguida, retorna essa matriz ao chamador. O chamador é minhaMotorOperations
classe, que por sua vez é chamada a partir de umaProductSelection
classe (que contém um algoritmo que é usado para seleccionar Motors, e informação sobre o motor é carregado os dados para que o algoritmo)Um objeto é uma coleção de métodos e dados com alta coesão. Eles pertencem a uma classe porque são altamente inter-relacionados e o estado é retido.
Isso é verdade se você usa um grande projeto inicial e tenta modelar tudo, ou um design emergente, onde itera e evolui o objeto para o que se adapta às necessidades do sistema no momento.
Se você não tiver motivos para reter o estado, provavelmente não terá motivos para instanciar um objeto, o que significa que provavelmente não há motivos para ter uma classe. A menos que o idioma que você está usando não tenha a capacidade de definir um espaço para nome que não seja a classe. Em que o uso de classe deve ser bom, porque seria idiomático.
Não consigo pensar em nenhum aspecto negativo do uso de classes dessa maneira, além do típico. Você está convidando custos e complexidade desnecessários ao instanciar um "espaço para nome". Qualquer pessoa que suporte esse código se perguntará onde os dados estão custando carga cognitiva adicional (provavelmente um custo único por pessoa). É um uso incomum, sem nenhum valor adicional.
fonte