{"id":615,"date":"2012-02-17T02:01:06","date_gmt":"2012-02-17T02:01:06","guid":{"rendered":"http:\/\/leonardocotta.com.br\/blog\/?p=615"},"modified":"2012-02-17T02:01:06","modified_gmt":"2012-02-17T02:01:06","slug":"php-padroes-o-padrao-observer","status":"publish","type":"post","link":"https:\/\/leonardocotta.com.br\/?p=615","title":{"rendered":"PHP: Padr\u00f5es O padr\u00e3o Observer"},"content":{"rendered":"<h3 align=\"left\">Introdu\u00e7\u00e3o<\/h3>\n<p>O padr\u00e3o Observer \u00e9 talvez o mais frequentemente encontrados em gr\u00e1fica de usu\u00e1rio tradicional<br \/>\naplica\u00e7\u00f5es de interface de desktop.\u00a0\u00c9 uma excelente maneira de garantir que disparate<br \/>\ncomponentes do visor refletir as mudan\u00e7as no n\u00facleo de um sistema.\u00a0Como veremos, por\u00e9m,<br \/>\ncontinua a ser uma t\u00e9cnica poderosa em um ambiente Web-oriented.<\/p>\n<p>Neste artigo eu mostrar-lhe como usar o padr\u00e3o Observer para construir uma flex\u00edvel<br \/>\ntransmiss\u00e3o estilo de rela\u00e7\u00e3o entre um componente central e os objetos que<br \/>\nse preocupam com isso.<\/p>\n<p>Primeiro, por\u00e9m, em prepara\u00e7\u00e3o para um exemplo de execu\u00e7\u00e3o, eu dou uma olhada no objeto<br \/>\nzombando de uma grande t\u00e9cnica para teste de condu\u00e7\u00e3o de c\u00f3digo.<!--more--><\/p>\n<p><a name=\"Heading3\"><\/a><\/p>\n<h3 align=\"left\">Exemplo de c\u00f3digo e um b\u00f4nus inesperado<\/h3>\n<p>Neste artigo, como voc\u00ea poderia esperar, eu cozinhei um exemplo para ilustrar<br \/>\nmeus pontos.\u00a0Esta \u00e9 sempre uma tarefa dif\u00edcil.\u00a0O exemplo deve ser cred\u00edvel<br \/>\no suficiente para que um leitor poderia imaginar que l\u00e1 fora no mundo real.\u00a0Por outro<br \/>\nPor outro lado, \u00e9 preciso muito sacrif\u00edcio que seria essencial no c\u00f3digo implantado no<br \/>\nselvagem.\u00a0O primeiro a ir \u00e9 geralmente verifica\u00e7\u00e3o de erros.\u00a0Ningu\u00e9m quer atrav\u00e9s de arado<br \/>\nmoitas de try \/ catch cl\u00e1usulas para chegar ao ponto simples enterrado dentro.\u00a0O<br \/>\nmesmo \u00e9 verdade para a funcionalidade incidental.\u00a0Em um artigo sobre a maneira que<br \/>\nobjetos e classes interagem, o processo de falar com um banco de dados ou de<br \/>\nan\u00e1lise de um documento XML \u00e9 muitas vezes irrelevantes.\u00a0Essa funcionalidade pode, muitas vezes<br \/>\nser substitu\u00edda por declara\u00e7\u00f5es de impress\u00e3o simples (&#8216;update db&#8217;, &#8216;ler documento XML&#8217;).<\/p>\n<p>Voc\u00ea pode achar um aviso deste tipo, em qualquer uma das centenas de t\u00e9cnico<br \/>\nartigos.\u00a0Tutorial c\u00f3digo \u00e9 voltada para compreens\u00e3o e n\u00e3o a implanta\u00e7\u00e3o.<br \/>\nNeste caso, por\u00e9m, ela serve para ilustrar um ponto.\u00a0Isto \u00e9: interface<br \/>\ndeve outrank aplica\u00e7\u00e3o em programa\u00e7\u00e3o orientada a objeto.\u00a0Na concep\u00e7\u00e3o de<br \/>\nseu c\u00f3digo, voc\u00ea pode tentar criar objetos que n\u00e3o fazem nada em tudo, mas imprimir<br \/>\nsuas a\u00e7\u00f5es se destinam.\u00a0Concentre-se nas classes em seu sistema e seus<br \/>\nrelacionamentos.\u00a0Em seguida, concentrar-se sobre as ac\u00e7\u00f5es que devem ser definidas.\u00a0Tire essa<br \/>\ndireito, e c\u00f3digo de implementa\u00e7\u00e3o, muitas vezes, caem no lugar naturalmente.<\/p>\n<p>Outro benef\u00edcio importante que voc\u00ea pode derivar dessa abordagem est\u00e1 em testes.<br \/>\nO teste de unidade em si \u00e9 um assunto para outro artigo.\u00a0No entanto, voc\u00ea deve<br \/>\nconsiderar estrat\u00e9gias para c\u00f3digo de constru\u00e7\u00e3o que automatiza testes de classe.\u00a0De todos<br \/>\nos problemas que podem aparecer em testar um componente, indiscutivelmente maiores do<br \/>\n\u00e9 contexto.\u00a0Um objeto raramente vive em isolamento, e ele pode precisar de trabalhar com<br \/>\noutros que falam a bases de dados, o sistema de arquivos ou solicita\u00e7\u00f5es HTTP.\u00a0Como fazer<br \/>\nde reproduzir essas condi\u00e7\u00f5es em um teste?\u00a0Uma maneira \u00e9 a de assegurar que uma real<br \/>\nRequisi\u00e7\u00e3o HTTP toma lugar, e um banco de dados real \u00e9 na m\u00e3o, abastecido com<br \/>\ndados v\u00e1lidos.\u00a0Isto sela aproxima\u00e7\u00e3o voc\u00ea com a sobrecarga de recriar um verdadeiro<br \/>\ncontexto mundial para a classe que voc\u00ea est\u00e1 testando, arrastando o seu foco na dire\u00e7\u00e3o errada.<\/p>\n<p>Se voc\u00ea est\u00e1 de codifica\u00e7\u00e3o para uma interface, no entanto, uma outra op\u00e7\u00e3o se abre.\u00a0Voc\u00ea pode<br \/>\ncriar objetos falsificados.\u00a0Se o c\u00f3digo que se comunica com seu banco de dados \u00e9 muito bem<br \/>\nencapsulado por tr\u00e1s de uma interface clara, ent\u00e3o n\u00e3o deve haver nada que impe\u00e7a<br \/>\nvoc\u00ea de criar uma classe que compartilha a mesma origem como a sua classe de banco de dados,<br \/>\nmas serve hard-coded dados para fins de teste.<\/p>\n<p>O exemplo para este artigo diz respeito uploads de arquivos.\u00a0Uma classe,\u00a0<code>UploadManager<\/code>\u00a0,<br \/>\ntrabalha com\u00a0<code>UploadFile<\/code>\u00a0objetos.\u00a0Aqui est\u00e1 o\u00a0<code>UploadFile<\/code>\u00a0abstrato<br \/>\nsuperclasse e uma implementa\u00e7\u00e3o simplificada:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\nabstract\u00a0class\u00a0UploadFile\u00a0{<\/code>&nbsp;<\/p>\n<p>tamanho\u00a0fun\u00e7\u00e3o abstrata\u00a0();<br \/>\nnome da\u00a0fun\u00e7\u00e3o abstrata ();<br \/>\nabstrata fun\u00e7\u00e3o\u00a0com erros\u00a0();<br \/>\nabstrata fun\u00e7\u00e3o\u00a0moveTo\u00a0($ str);<br \/>\n}<\/p>\n<p>UploadFileException\u00a0classe\u00a0extends\u00a0Exception\u00a0{}<\/p>\n<p>UploadFileImpl\u00a0classe\u00a0extends\u00a0UploadFile\u00a0{<\/p>\n<p>private\u00a0$\u00a0formFieldName;<br \/>\nprivate\u00a0$ fsPath\u00a0=\u00a0null;<\/p>\n<p>constru\u00e7\u00e3o\u00a0da fun\u00e7\u00e3o\u00a0__\u00a0($ formFieldName)\u00a0{<\/p>\n<p>if (! isset\u00a0($ _FILES\u00a0[$ formFieldName]))\u00a0{<br \/>\nthrow new\u00a0UploadFileException\u00a0(&#8220;formFieldName\u00a0$\u00a0desconhecida&#8221;);<br \/>\n}<br \/>\n$ This\u00a0-&gt;\u00a0formFieldName\u00a0=\u00a0$\u00a0formFieldName;<br \/>\n}<\/p>\n<p>tamanho\u00a0function\u00a0() {<br \/>\nretornar\u00a0$ _FILES\u00a0[$\u00a0this\u00a0-&gt;\u00a0formFieldName]\u00a0[&#8216;size&#8217;];<br \/>\n}<\/p>\n<p>nome\u00a0function\u00a0() {<br \/>\nretornar\u00a0$ _FILES\u00a0[$\u00a0this\u00a0-&gt;\u00a0formFieldName]\u00a0[&#8216;name&#8217;];<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0com erros\u00a0() {<br \/>\nretornar\u00a0$ _FILES\u00a0[$\u00a0this\u00a0-&gt;\u00a0formFieldName]\u00a0[&#8216;error&#8217;];<br \/>\n}<\/p>\n<p>caminho\u00a0function\u00a0() {<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0fsPath;<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0moveTo\u00a0($ perm_loc)\u00a0{<\/p>\n<p>if (!\u00a0<a href=\"http:\/\/translate.googleusercontent.com\/translate_c?hl=pt-BR&amp;prev=\/search%3Fq%3Ddesign%2Bpatterns%2Bobserver%2Bphp%26hl%3Dpt-BR%26client%3Dubuntu%26hs%3DfPt%26channel%3Dcs%26biw%3D1366%26bih%3D681%26prmd%3Dimvns&amp;rurl=translate.google.com.br&amp;sl=en&amp;u=http:\/\/www.zend.com\/manual\/function.is-null.php&amp;usg=ALkJrhgV8AVVSOQIlYRd1_cESBMjXmhaug\" target=\"_blank\" rel=\"noopener\">is_null<\/a>\u00a0($\u00a0this\u00a0-&gt;\u00a0fsPath))\u00a0{<br \/>\nreturn\u00a0null;<br \/>\n}<\/p>\n<p>if (\u00a0<a href=\"http:\/\/translate.googleusercontent.com\/translate_c?hl=pt-BR&amp;prev=\/search%3Fq%3Ddesign%2Bpatterns%2Bobserver%2Bphp%26hl%3Dpt-BR%26client%3Dubuntu%26hs%3DfPt%26channel%3Dcs%26biw%3D1366%26bih%3D681%26prmd%3Dimvns&amp;rurl=translate.google.com.br&amp;sl=en&amp;u=http:\/\/www.zend.com\/manual\/function.is-dir.php&amp;usg=ALkJrhj8kSAZ-yYgcCGLII_3nzaeF0OROQ\" target=\"_blank\" rel=\"noopener\">is_dir<\/a>\u00a0($ perm_loc))\u00a0{<br \/>\n$ Perm_loc\u00a0=\u00a0DIRECTORY_SEPARATOR $ this\u00a0-&gt;\u00a0name\u00a0()..;<br \/>\n}<\/p>\n<p><a href=\"http:\/\/translate.googleusercontent.com\/translate_c?hl=pt-BR&amp;prev=\/search%3Fq%3Ddesign%2Bpatterns%2Bobserver%2Bphp%26hl%3Dpt-BR%26client%3Dubuntu%26hs%3DfPt%26channel%3Dcs%26biw%3D1366%26bih%3D681%26prmd%3Dimvns&amp;rurl=translate.google.com.br&amp;sl=en&amp;u=http:\/\/www.zend.com\/manual\/function.move-uploaded-file.php&amp;usg=ALkJrhhZxcY9djCCtReYJqG-6ldgkytdOQ\" target=\"_blank\" rel=\"noopener\">move_uploaded_file<\/a>\u00a0($\u00a0_FILES\u00a0[$\u00a0this\u00a0-&gt;\u00a0formFieldName]\u00a0[&#8216;tmp_name&#8217;],\u00a0$\u00a0perm_loc);<\/p>\n<p>if (\u00a0<a href=\"http:\/\/translate.googleusercontent.com\/translate_c?hl=pt-BR&amp;prev=\/search%3Fq%3Ddesign%2Bpatterns%2Bobserver%2Bphp%26hl%3Dpt-BR%26client%3Dubuntu%26hs%3DfPt%26channel%3Dcs%26biw%3D1366%26bih%3D681%26prmd%3Dimvns&amp;rurl=translate.google.com.br&amp;sl=en&amp;u=http:\/\/www.zend.com\/manual\/function.is-file.php&amp;usg=ALkJrhjJMt0p7HwC1WiYEuNvUN0Dr4XQAg\" target=\"_blank\" rel=\"noopener\">is_file<\/a>\u00a0($ perm_loc))\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0fsPath\u00a0=\u00a0<a href=\"http:\/\/translate.googleusercontent.com\/translate_c?hl=pt-BR&amp;prev=\/search%3Fq%3Ddesign%2Bpatterns%2Bobserver%2Bphp%26hl%3Dpt-BR%26client%3Dubuntu%26hs%3DfPt%26channel%3Dcs%26biw%3D1366%26bih%3D681%26prmd%3Dimvns&amp;rurl=translate.google.com.br&amp;sl=en&amp;u=http:\/\/www.zend.com\/manual\/function.realpath.php&amp;usg=ALkJrhhuVuA-mMXvJWNAyOHAjA6fxvrtRQ\" target=\"_blank\" rel=\"noopener\">realpath<\/a>\u00a0($ perm_loc);<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0fsPath;<br \/>\n}<\/p>\n<p>return\u00a0null;<br \/>\n}<br \/>\n}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>O\u00a0<code>UploadFileImpl<\/code>\u00a0classe \u00e9 um wrapper simples em torno de um elemento de<br \/>\no\u00a0<code>$_FILES<\/code>\u00a0matriz que \u00e9 preenchido automaticamente pelo mecanismo de PHP<br \/>\nquando um upload HTTP ocorre.\u00a0A classe fornece informa\u00e7\u00f5es sobre o arquivo carregado,<br \/>\ne suporta mov\u00ea-lo de seu local de armazenamento tempor\u00e1rio para um mais permanente<br \/>\ncasa no sistema de arquivos.<\/p>\n<p>Esta classe \u00e9 simples e compacta o suficiente para usar nos exemplos, mas sofre de<br \/>\numa grande desvantagem quando usado em testes e demonstra\u00e7\u00f5es.\u00a0Ele requer um arquivo de upload<br \/>\nter ocorrido.\u00a0O fato de que o\u00a0<code>UploadFileImpl<\/code>\u00a0classe estende<br \/>\numa superclasse abstrata fornece-nos uma oportunidade.\u00a0Podemos criar um boneco<br \/>\nupload de classe que estende o mesmo pai.\u00a0Qualquer cliente deve ser capaz de usar este<br \/>\nalternadamente com a coisa real.\u00a0Aulas fict\u00edcias s\u00e3o conhecidas como\u00a0<strong>as simula\u00e7\u00f5es.<\/strong><br \/>\nAqui est\u00e1\u00a0<code>MockUploadFile<\/code>\u00a0:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\nclass MockUploadFile\u00a0extends\u00a0UploadFile\u00a0{<\/code>&nbsp;<\/p>\n<p>$ tamanho\u00a0privada\u00a0=\u00a03000;<br \/>\nprivate\u00a0$ fspath\u00a0=\u00a0null;<br \/>\n$ name\u00a0privado =\u00a0&#8216;mock.gif&#8217;;<br \/>\nprivate\u00a0$ errorCode\u00a0=\u00a0null;<br \/>\n$\u00a0privado\u00a0moveToResult\u00a0=\u00a0true;<\/p>\n<p>constru\u00e7\u00e3o\u00a0da fun\u00e7\u00e3o\u00a0__\u00a0($ name)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0nome\u00a0=\u00a0$\u00a0nome;<br \/>\n}<\/p>\n<p>setSize\u00a0fun\u00e7\u00e3o\u00a0($ tamanho)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0size\u00a0=\u00a0$\u00a0tamanho;<br \/>\n}<\/p>\n<p>tamanho\u00a0function\u00a0() {<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0tamanho;<br \/>\n}<\/p>\n<p>setName\u00a0fun\u00e7\u00e3o\u00a0($ name)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0nome\u00a0=\u00a0$\u00a0nome;<br \/>\n}<\/p>\n<p>nome\u00a0function\u00a0() {<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0nome;<br \/>\n}<\/p>\n<p>setErrorCode\u00a0fun\u00e7\u00e3o\u00a0($ code)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0errorCode code\u00a0=\u00a0$;<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0com erros\u00a0() {<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0errorCode;<br \/>\n}<\/p>\n<p>caminho\u00a0function\u00a0() {<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0fsPath;<br \/>\n}<\/p>\n<p>setMoveToFail\u00a0function\u00a0() {<br \/>\n$ This\u00a0-&gt;\u00a0moveToFail\u00a0=\u00a0true;<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0moveTo\u00a0($ path)\u00a0{<\/p>\n<p>if\u00a0($ this\u00a0-&gt;\u00a0com erros\u00a0() | |!\u00a0<a href=\"http:\/\/translate.googleusercontent.com\/translate_c?hl=pt-BR&amp;prev=\/search%3Fq%3Ddesign%2Bpatterns%2Bobserver%2Bphp%26hl%3Dpt-BR%26client%3Dubuntu%26hs%3DfPt%26channel%3Dcs%26biw%3D1366%26bih%3D681%26prmd%3Dimvns&amp;rurl=translate.google.com.br&amp;sl=en&amp;u=http:\/\/www.zend.com\/manual\/function.is-null.php&amp;usg=ALkJrhgV8AVVSOQIlYRd1_cESBMjXmhaug\" target=\"_blank\" rel=\"noopener\">is_null<\/a>\u00a0($\u00a0this\u00a0-&gt;\u00a0fsPath))\u00a0{<br \/>\nreturn\u00a0null;<br \/>\n}<\/p>\n<p>return\u00a0$ this\u00a0-&gt;\u00a0fsPath path\u00a0=\u00a0$;<br \/>\n}<br \/>\n}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Observe que esta classe de simula\u00e7\u00e3o \u00e9 configur\u00e1vel.\u00a0Podemos definir os valores-chave, que pode at\u00e9 causar<br \/>\nopera\u00e7\u00f5es para falhar se queremos.\u00a0Porque eles podem ser configurados para criar condi\u00e7\u00f5es de erro,<br \/>\ntais classes pode agir como espi\u00f5es ou provocadores agentes no campo inimigo.\u00a0Podemos enviar<br \/>\n-los para causar problemas, ent\u00e3o sentar e ver o caos que se seguiu desdobrar.<\/p>\n<p>A Figura 1 mostra o\u00a0<code>UploadFile<\/code>\u00a0tipo em conjunto com um cliente insuspeito<br \/>\nclasse.\u00a0O cliente \u00e9 passado um\u00a0<code>UploadFile<\/code>\u00a0objeto e continua alegremente<br \/>\ndesconhece a implementa\u00e7\u00e3o em particular com o qual trabalha.\u00a0\u00c9 por isso que \u00e9<br \/>\ngeralmente uma boa id\u00e9ia para passar objetos em torno de um sistema em vez de t\u00ea-los instanciado<br \/>\ndiretamente pelas classes que os utilizam.\u00a0Claro que os objetos devem ser instanciados em algum lugar,<br \/>\ne de acordo com alguma l\u00f3gica.\u00a0Vamos olhar para algumas destas estrat\u00e9gias em um artigo posterior.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/devzone.zend.com\/content\/images\/mzandstra\/patterns2-1.jpg\" alt=\"A Figura 1\" border=\"0\" \/><\/p>\n<p><a name=\"Heading4\"><\/a><\/p>\n<h3 align=\"left\">O padr\u00e3o Observer<\/h3>\n<p>Descrito pelo Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides)<br \/>\nem seu cat\u00e1logo seminal,\u00a0<em>Design Patterns.<\/em>\u00a0<em>Elementos de Software Orientada a Objetos reutiliz\u00e1veis<\/em><br \/>\n(Addison Wesley, 1995), este padr\u00e3o \u00e9 um exemplo fant\u00e1stico de dissocia\u00e7\u00e3o em a\u00e7\u00e3o.<\/p>\n<p>Um dos grandes objetivos do programador orientado a objeto \u00e9 criar ortogonal<br \/>\ncomponentes.\u00a0Isso significa que a coes\u00e3o elevada (cada componente est\u00e1 ligado a si mesmo e um n\u00facleo<br \/>\nprop\u00f3sito) e acoplamento fraco (os componentes s\u00e3o independentes de seu contexto poss\u00edvel).<br \/>\nEsta compra nos componentes que podem ser reutilizados facilmente, e talvez mais importante que pode<br \/>\nlevar a sistemas que s\u00e3o flex\u00edveis e menos propenso a erros.\u00a0Quando, em contrapartida o maior<br \/>\nsistema \u00e9 permitida a enraizar-se em um componente, tamb\u00e9m h\u00e1 uma teia de interdepend\u00eancia.Se<br \/>\num componente \u00e9 muito acolhedor, com seu contexto, n\u00e3o pode facilmente ser puxado para longe dele.<br \/>\nAl\u00e9m disso, fazer uma mudan\u00e7a em uma parte de um sistema pode levar a n\u00e3o intencional<br \/>\nconseq\u00fc\u00eancias em outros lugares.<\/p>\n<p>Todos n\u00f3s j\u00e1 encontramos sistemas que as declara\u00e7\u00f5es de pimenta SQL em todos os componentes.Tal<br \/>\ncodifica\u00e7\u00e3o prom\u00edscuo \u00e9 tentador.\u00a0\u00c9 mais f\u00e1cil de consultar um banco de dados como e quando voc\u00ea precisar<br \/>\npara que a elaborar uma estrat\u00e9gia centralizada.\u00a0O sal\u00e1rio do pecado, no entanto, s\u00e3o trabalhar e<br \/>\nerro.\u00a0A mudan\u00e7a de esquema simples de banco de dados pode exigir mudan\u00e7as para a direita em todo o sistema,<br \/>\ncom o risco inevit\u00e1vel que uma afirma\u00e7\u00e3o obscura ou dois \u00e9 perdido.\u00a0Perdida, isto \u00e9,<br \/>\nat\u00e9 a manh\u00e3 de apresentar a sua fant\u00e1stica aplica\u00e7\u00e3o nova para um cliente ou um investidor.<\/p>\n<p>A dissocia\u00e7\u00e3o, ent\u00e3o, \u00e9 o processo pelo qual voc\u00ea separar componentes de seus contextos,<br \/>\neo padr\u00e3o Observer \u00e9 uma estrat\u00e9gia que voc\u00ea deve ter em sua caixa de ferramentas dissocia\u00e7\u00e3o.<\/p>\n<p><a name=\"Heading5\"><\/a><\/p>\n<h4 align=\"left\">Vis\u00e3o global<\/h4>\n<p>O padr\u00e3o Observer define um mecanismo atrav\u00e9s do qual os componentes podem optar por receber<br \/>\nmensagens quando um objeto alvo (confusamente conhecido como o\u00a0<em>assunto)<\/em>\u00a0altera a sua<br \/>\nEstado.\u00a0O sujeito precisa ter nenhum conhecimento de &#8216;observar&#8217; os componentes-lo para eventos,<br \/>\nal\u00e9m do fato de que eles est\u00e3o l\u00e1 e apoiar uma interface para notifica\u00e7\u00e3o.<\/p>\n<p><a name=\"Heading6\"><\/a><\/p>\n<h4 align=\"left\">O Problema<\/h4>\n<p>Imagine que voc\u00ea est\u00e1 construindo um site de comunidade de m\u00fasica que permite aos usu\u00e1rios fazer upload de seu trabalho<br \/>\npara o compartilhamento e avalia\u00e7\u00e3o.\u00a0Para este efeito, voc\u00ea criou o\u00a0<code>UploadFile<\/code><br \/>\naulas j\u00e1 vimos, e agora precisamos gerenciar o upload.\u00a0H\u00e1 alguns<br \/>\nquest\u00f5es leg\u00edtimas que um\u00a0<code>UploadManager<\/code>\u00a0classe deve atender.\u00a0Ele deve:<\/p>\n<ul>\n<li>verificar se um usu\u00e1rio n\u00e3o tiver preenchido sua cota de espa\u00e7o<\/li>\n<li>invocar\u00a0<code>UploadFile::moveTo()<\/code><\/li>\n<li>verificar se h\u00e1 erros de upload<\/li>\n<li>atualizar as informa\u00e7\u00f5es do usu\u00e1rio espa\u00e7o em disco<\/li>\n<\/ul>\n<p>Aqui est\u00e1 uma implementa\u00e7\u00e3o:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\nclass UploadManager\u00a0{<\/code>&nbsp;<\/p>\n<p>$ user\u00a0privado;<br \/>\nprivate\u00a0$\u00a0repDir;<br \/>\n$ status\u00a0private =\u00a00;<\/p>\n<p>const\u00a0UM_UPLOAD_ERROR\u00a0=\u00a01;<br \/>\nconst\u00a0UM_QUOTA_ERROR\u00a0=\u00a02;<\/p>\n<p>function\u00a0__ construct\u00a0(Usu\u00e1rio\u00a0$\u00a0user,\u00a0$\u00a0reposit\u00f3rio)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0user =\u00a0$\u00a0user;<br \/>\n$ This\u00a0-&gt;\u00a0repDir reposit\u00f3rio\u00a0=\u00a0$;<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0processFile\u00a0(UploadFile\u00a0$\u00a0arquivo)\u00a0{<\/p>\n<p>$ This\u00a0-&gt;\u00a0afirmar\u00a0(($\u00a0file\u00a0-&gt;\u00a0size\u00a0()\u00a0&lt;$\u00a0this\u00a0-&gt;\u00a0user -&gt;\u00a0dispon\u00edvel\u00a0()),\u00a0&#8216;quota do usu\u00e1rio excedida\u00a0&#8220;,self\u00a0::\u00a0UM_QUOTA_ERROR);<\/p>\n<p>$ File\u00a0-&gt;\u00a0moveTo\u00a0($\u00a0this\u00a0-&gt;\u00a0repDir);<\/p>\n<p>$ This\u00a0-&gt;\u00a0afirmar\u00a0(($\u00a0errorcode\u00a0=\u00a0$ file\u00a0-&gt;\u00a0com erros\u00a0()),\u00a0&#8220;Arquivo de erro de upload: $\u00a0errorcode!&#8221;,Self\u00a0::\u00a0UM_UPLOAD_ERROR);<\/p>\n<p>$ This\u00a0&#8211;\u00a0status&gt;\u00a0=\u00a00;<br \/>\n$ This\u00a0-&gt;\u00a0user\u00a0-&gt;\u00a0setStored\u00a0($\u00a0this\u00a0-&gt;\u00a0user\u00a0-&gt;\u00a0armazenado\u00a0() +\u00a0$ arquivo\u00a0-&gt;\u00a0size\u00a0());<br \/>\nreturn\u00a0true;<br \/>\n}<\/p>\n<p>funcionar\u00a0assert\u00a0($ condition,\u00a0$\u00a0msg,\u00a0$\u00a0code)\u00a0{<\/p>\n<p>if (!\u00a0$\u00a0condition)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0Status\u00a0code\u00a0=\u00a0$;<br \/>\njogar\u00a0UploadFileException\u00a0novo\u00a0($ msg,\u00a0$\u00a0code);<br \/>\n}<br \/>\n}<\/p>\n<p>estado\u00a0function () {<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0Estado;<br \/>\n}<br \/>\n}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>O cora\u00e7\u00e3o desta classe \u00e9 o\u00a0<code>processFile()<\/code>\u00a0m\u00e9todo.\u00a0Ele verifica dispon\u00edvel<br \/>\ncota de espa\u00e7o, as tentativas para instalar o arquivo carregado, verifica os erros e atualiza\u00e7\u00f5es<br \/>\ninforma\u00e7\u00f5es de armazenamento do usu\u00e1rio.<\/p>\n<p>Aqui est\u00e1 um simples\u00a0<code>User<\/code>\u00a0de classe que trabalha com\u00a0<code>UploadManager<\/code>\u00a0:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\nclass User\u00a0{<\/code>&nbsp;<\/p>\n<p>quota $\u00a0privado;<br \/>\n$\u00a0privadas\u00a0armazenadas\u00a0=\u00a00;<\/p>\n<p>function\u00a0__ construct\u00a0($\u00a0quota\u00a0=\u00a050000)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0quota quota\u00a0=\u00a0$;<br \/>\n}<\/p>\n<p>quota\u00a0function\u00a0() {<br \/>\nreturn\u00a0$ this\u00a0&#8211;\u00a0quota&gt;;<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0dispon\u00edvel\u00a0() {<br \/>\nreturn\u00a0($\u00a0this\u00a0-&gt;\u00a0quota\u00a0&#8211;\u00a0$ this\u00a0-&gt;\u00a0armazenados);<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0setStored\u00a0($ quantidade)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0armazenada quantidade\u00a0=\u00a0$;<br \/>\n}<\/p>\n<p>fun\u00e7\u00e3o\u00a0armazenada\u00a0() {<br \/>\nreturn\u00a0$ this\u00a0-&gt;\u00a0armazenado;<br \/>\n}<br \/>\n}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Como voc\u00ea pode ver, esta classe foi cortar at\u00e9 o osso para que ele s\u00f3 suporta arquivos<br \/>\nfuncionalidade de armazenamento.\u00a0Podemos consultar um\u00a0<code>User<\/code>\u00a0objeto para descobrir mais sobre sua<br \/>\nquota, ea quantidade de armazenamento que tem em uso e dispon\u00edveis.\u00a0<code>UploadManager<\/code><br \/>\nchama esses m\u00e9todos para assegurar que o utilizador actual tem um espa\u00e7o adequado para armazenar o<br \/>\nsubmetidos clipe.<\/p>\n<p>Aqui est\u00e1 um c\u00f3digo que coloca as classes com seus ritmos:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\n$user\u00a0= new\u00a0User\u00a0(\u00a04000\u00a0);<br \/>\n$mgr\u00a0= new\u00a0UploadManager\u00a0(\u00a0$user\u00a0,\u00a0'\/tmp'\u00a0);<br \/>\n$file\u00a0= new\u00a0MockUploadFile\u00a0(\u00a0\"test.gif\"\u00a0);<\/code>&nbsp;<\/p>\n<p>if\u00a0($ mgr\u00a0-&gt;\u00a0processFile\u00a0($ arquivo))\u00a0{<br \/>\nprint\u00a0&#8220;OK \u00a0n&#8221;;<br \/>\n}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Criamos um novo\u00a0<code>User<\/code>\u00a0objeto com uma cota de armazenamento de 4000 e pass\u00e1-lo para o<br \/>\n<code>UploadManager<\/code>\u00a0m\u00e9todo construtor.\u00a0Finalmente criamos um objeto de arquivo e invocar<br \/>\n<code>UploadManager::processFile()<\/code>\u00a0.\u00a0Esta amostra simplesmente gera &#8216;OK&#8217;.\u00a0N\u00f3s podemos fazer<br \/>\nas coisas mais interessantes, embora por envenenar nosso\u00a0<code>MockUploadFile<\/code>\u00a0objeto.\u00a0Este<br \/>\ndefine o tamanho do arquivo para al\u00e9m do contingente do usu\u00e1rio:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\n\/\/...<br \/>\n$file\u00a0-&gt;\u00a0setSize\u00a0(\u00a05000\u00a0);\u00a0\/\/ TOO HIGH!!<\/code>&nbsp;<\/p>\n<p>if\u00a0($\u00a0mgr\u00a0-&gt;\u00a0processFile\u00a0($ arquivo))\u00a0{<br \/>\nprint\u00a0&#8220;OK \u00a0n&#8221;;<br \/>\n}<\/p>\n<p>\/ \/ Output:<br \/>\n\/ \/ Erro Fatal: Exce\u00e7\u00e3o Uncaught<br \/>\n\/ \/ &#8216;UploadFileException&#8217; com mensagem<br \/>\n\/ \/ &#8216;Quota do usu\u00e1rio excedida&#8217; dentro ..<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Aqui n\u00f3s fingimos um erro de upload de arquivos:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\n$file\u00a0-&gt;\u00a0setErrorCode\u00a0(\u00a0UPLOAD_ERR_PARTIAL\u00a0);<\/code>&nbsp;<\/p>\n<p>if\u00a0($ mgr\u00a0-&gt;\u00a0processFile\u00a0($ arquivo))\u00a0{<br \/>\nprint\u00a0&#8220;OK \u00a0n&#8221;;<br \/>\n}<\/p>\n<p>\/ \/ Output: Fatal error: Uncaught exce\u00e7\u00e3o<br \/>\n\/ \/ &#8216;UploadFileException&#8217; com mensagem<br \/>\n\/ \/ &#8216;File upload de erro: 3&#8217; polegadas ..<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>At\u00e9 agora, as principais classes do exemplo ter permanecido razoavelmente centrada na sua<br \/>\npr\u00f3prias preocupa\u00e7\u00f5es.\u00a0Talvez\u00a0<code>UploadManager<\/code>\u00a0pode delegar um pouco \u00fatil<br \/>\nmais para\u00a0<code>User<\/code>\u00a0, mas isso \u00e9 uma mudan\u00e7a f\u00e1cil de fazer a qualquer momento.\u00a0Acoplamento<br \/>\nest\u00e1 solto, em que nenhum componente instancia outro, deixando ampla oportunidade para<br \/>\nmudan\u00e7a de classe por tr\u00e1s claras e interfaces bem definidas.\u00a0A Figura 2 ilustra o<br \/>\nrela\u00e7\u00f5es de uso.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/devzone.zend.com\/content\/images\/mzandstra\/patterns2-2.jpg\" alt=\"A Figura 2\" border=\"0\" \/><\/p>\n<p>Agora vamos introduzir algumas moscas no ung\u00fcento.\u00a0O grupo empresarial encontrar mais dinheiro<br \/>\npara o projeto e estender seu curta.\u00a0A partir de agora, todos os envios devem ser registrados.<br \/>\nNotifica\u00e7\u00e3o de transa\u00e7\u00f5es falhas devem ser enviadas por e-mail para o pessoal designado.<br \/>\nUploads de sucesso deve agendar uma mensagem a ser enviada atrav\u00e9s de servi\u00e7os Web a um ter\u00e7o<br \/>\nparceiro do partido, mas somente enquanto o acordo de parceria continua.<\/p>\n<p>\u00c9 muitas vezes novas funcionalidades que matar um projeto.\u00a0<code>UploadManager<\/code>\u00a0\u00e9 certamente<br \/>\num lugar \u00fatil para pendurar todas estas fun\u00e7\u00f5es, mas o que faz esta m\u00e1gica para o sistema<br \/>\ncomo um todo?\u00a0Logging pode ser algo que voc\u00ea poderia esperar objetos de neg\u00f3cios para<br \/>\nconhecemos, mas os detalhes em constante mudan\u00e7a de detalhes de parceria corporativa pode empurrar<br \/>\nas coisas um pouco.\u00a0\u00c9 o seu trabalho para acomodar esta l\u00f3gica, mas como voc\u00ea pode faz\u00ea-lo<br \/>\nflex\u00edvel?\u00a0Aqui est\u00e1 uma vers\u00e3o alterada do principais m\u00e9todos da classe:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code><br \/>\nfunction\u00a0processFile\u00a0(\u00a0UploadFile $file\u00a0) {<\/code>&nbsp;<\/p>\n<p>$ File\u00a0-&gt;\u00a0moveTo\u00a0($\u00a0this\u00a0-&gt;\u00a0repDir);<\/p>\n<p>$ This\u00a0-&gt;\u00a0afirmar\u00a0(($\u00a0file\u00a0-&gt;\u00a0size\u00a0()\u00a0&lt;$\u00a0this\u00a0-&gt;\u00a0user -&gt;\u00a0dispon\u00edvel\u00a0()),\u00a0&#8216;quota do usu\u00e1rio excedida\u00a0&#8220;,self\u00a0::\u00a0UM_QUOTA_ERROR);<\/p>\n<p>$ This\u00a0-&gt;\u00a0afirmar\u00a0(($\u00a0errorcode\u00a0=\u00a0$ file\u00a0-&gt;\u00a0com erros\u00a0()),\u00a0&#8220;Arquivo de erro de upload: $\u00a0errorcode!&#8221;,Self\u00a0::\u00a0UM_UPLOAD_ERROR);<\/p>\n<p>if\u00a0(PARTNERSHIP_DEAL)\u00a0{<br \/>\n$ Relay\u00a0= new\u00a0PartnershipRelay\u00a0();<br \/>\n$ Rel\u00e9\u00a0-&gt;\u00a0informar\u00a0($ file,\u00a0$\u00a0user);<br \/>\n}<\/p>\n<p>Logger\u00a0::\u00a0instance () -&gt;\u00a0<a href=\"http:\/\/translate.googleusercontent.com\/translate_c?hl=pt-BR&amp;prev=\/search%3Fq%3Ddesign%2Bpatterns%2Bobserver%2Bphp%26hl%3Dpt-BR%26client%3Dubuntu%26hs%3DfPt%26channel%3Dcs%26biw%3D1366%26bih%3D681%26prmd%3Dimvns&amp;rurl=translate.google.com.br&amp;sl=en&amp;u=http:\/\/www.zend.com\/manual\/function.log.php&amp;usg=ALkJrhij80lFr6xvsI4HoDMDo3gGB0kMtg\" target=\"_blank\" rel=\"noopener\">log<\/a>\u00a0($\u00a0file\u00a0-&gt;\u00a0name\u00a0().\u00a0&#8220;:\u00a0carregado&#8221;);<\/p>\n<p>$ This\u00a0&#8211;\u00a0status&gt;\u00a0=\u00a00;<br \/>\n$ This\u00a0-&gt;\u00a0user\u00a0-&gt;\u00a0setStored\u00a0($\u00a0this\u00a0-&gt;\u00a0user\u00a0-&gt;\u00a0armazenado\u00a0() +\u00a0$ arquivo\u00a0-&gt;\u00a0size\u00a0());<br \/>\nreturn\u00a0true;<br \/>\n}<\/p>\n<p>funcionar\u00a0assert\u00a0($ condition,\u00a0$\u00a0msg,\u00a0$\u00a0code)\u00a0{<\/p>\n<p>if (!\u00a0$\u00a0condition)\u00a0{<br \/>\n$ This\u00a0-&gt;\u00a0Status\u00a0code\u00a0=\u00a0$;<br \/>\nLogger\u00a0::\u00a0instance () -&gt;\u00a0erro\u00a0($ msg,\u00a0$\u00a0code);<br \/>\n$ Informante\u00a0= new\u00a0Informer\u00a0();<br \/>\n$ Informante\u00a0-&gt;\u00a0mailwarning\u00a0($ msg,\u00a0$\u00a0code);<br \/>\njogar\u00a0UploadFileException\u00a0novo\u00a0($ msg,\u00a0$\u00a0code);<br \/>\n}<br \/>\n}<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Como voc\u00ea pode ver, o\u00a0<code>UploadManager<\/code>\u00a0classe tornou-se atolada em seu contexto.\u00a0Ele<br \/>\n\u00e9 confiar num constante,\u00a0<code>PARTNERSHIP_DEAL<\/code>\u00a0, bem como fazendo algum directa<br \/>\ninstancia\u00e7\u00f5es.\u00a0Poder\u00edamos corrigir esses problemas por ter objetos passados, ou servido<br \/>\npor m\u00e9todos de f\u00e1brica (mais sobre isso em artigos futuros), mas uma quest\u00e3o central continuar\u00e1 a ser:<br \/>\n<code>UploadManager<\/code>\u00a0sabe demais.\u00a0A classe tornou-se espec\u00edfica site.\u00a0N\u00f3s<br \/>\nn\u00e3o poderia facilmente busc\u00e1-lo e solt\u00e1-lo em outro sistema similar, pois ele agora<br \/>\nbaseia-se explicitamente sobre muitas classes e m\u00e9todos que s\u00e3o incidentais ao seu n\u00facleo<br \/>\nfinalidade.\u00a0A Figura 3 ilustra o problema.<\/p>\n<p>&nbsp;<\/p>\n<p>http:\/\/devzone.zend.com\/362\/php-patterns_the-observer-pattern\/<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introdu\u00e7\u00e3o O padr\u00e3o Observer \u00e9 talvez o mais frequentemente encontrados em gr\u00e1fica de usu\u00e1rio tradicional aplica\u00e7\u00f5es de interface de desktop.\u00a0\u00c9 uma excelente maneira de garantir que disparate componentes do visor refletir as mudan\u00e7as no n\u00facleo de um sistema.\u00a0Como veremos, por\u00e9m, continua a ser uma t\u00e9cnica poderosa em um ambiente Web-oriented. Neste artigo eu mostrar-lhe como &hellip; <a href=\"https:\/\/leonardocotta.com.br\/?p=615\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">PHP: Padr\u00f5es O padr\u00e3o Observer<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[55],"tags":[80,199],"class_list":["post-615","post","type-post","status-publish","format-standard","hentry","category-observer","tag-codigo","tag-padroes"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=\/wp\/v2\/posts\/615","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=615"}],"version-history":[{"count":0,"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=\/wp\/v2\/posts\/615\/revisions"}],"wp:attachment":[{"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=615"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=615"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/leonardocotta.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=615"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}