Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > it.comp.www.php > #20682 > unrolled thread

trait per decoratore standard

Started byalex <1j9448a02@lnx159sneakemail.com.invalid>
First post2016-04-22 11:10 +0200
Last post2016-04-22 07:58 -0700
Articles 20 on this page of 53 — 3 participants

Back to article view | Back to it.comp.www.php


Contents

  trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-22 11:10 +0200
    Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-22 10:36 +0100
      Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-22 12:08 +0200
        Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-22 14:39 +0100
          Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-22 16:31 +0200
            Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-22 18:16 +0100
              Re: trait per decoratore standard fmassei@gmail.com - 2016-04-22 10:58 -0700
                Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-22 20:00 +0000
                  Re: trait per decoratore standard fmassei@gmail.com - 2016-04-22 14:01 -0700
                    Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-23 17:56 +0000
                      Re: trait per decoratore standard fmassei@gmail.com - 2016-04-24 22:16 -0700
                        Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-25 14:10 +0100
                Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-22 22:26 +0200
              Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-22 22:18 +0200
                Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-22 20:46 +0000
                  Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-23 10:30 +0200
                    Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-23 11:07 +0200
                      Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-23 11:32 +0200
                      Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-23 17:50 +0000
                        Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-24 10:36 +0200
                          Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-24 10:50 +0200
                          Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-24 11:28 +0000
                            Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-24 18:48 +0200
                          Re: trait per decoratore standard fmassei@gmail.com - 2016-04-24 22:19 -0700
                    Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-23 17:45 +0000
                      Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-24 10:26 +0200
                        Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-24 11:26 +0000
                          Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-26 14:50 +0200
                            Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-26 15:07 +0100
                              Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-26 21:11 +0200
                                Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-26 19:31 +0000
                                  Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-26 22:02 +0200
                                    Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-26 20:39 +0000
                                      Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-27 16:10 +0200
                                        Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-27 15:16 +0100
                                          Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-27 17:26 +0200
                      Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-29 17:42 +0200
                        Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-29 17:12 +0100
                          Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-30 13:20 +0200
                        Re: trait per decoratore standard fmassei@gmail.com - 2016-04-30 08:06 -0700
                          Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-30 21:26 +0200
                            Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-30 19:42 +0000
                              Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-30 23:20 +0200
                                Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-30 21:43 +0000
                                  Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-05-01 10:34 +0200
                              Re: trait per decoratore standard fmassei@gmail.com - 2016-04-30 14:38 -0700
                                Re: trait per decoratore standard Alessandro Pellizzari <shuriken@amiran.it> - 2016-04-30 21:41 +0000
                                Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-05-01 10:45 +0200
                                  Re: trait per decoratore standard fmassei@gmail.com - 2016-05-01 09:02 -0700
                                    Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-05-02 10:45 +0200
        Re: trait per decoratore standard fmassei@gmail.com - 2016-04-22 07:12 -0700
          Re: trait per decoratore standard alex <1j9448a02@lnx159sneakemail.com.invalid> - 2016-04-22 16:44 +0200
            Re: trait per decoratore standard fmassei@gmail.com - 2016-04-22 07:58 -0700

Page 1 of 3  [1] 2 3  Next page →


#20682 — trait per decoratore standard

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-22 11:10 +0200
Subjecttrait per decoratore standard
Message-ID<nfcppf$1vs$1@gioia.aioe.org>
<?php
trait StandardDecoratorTrait {
	function __construct(parent $wrapped) {
		$this->_wrapped = $wrapped;
	}
}

abstract class Component {
	//abstract function...
}

class GenericComponent extends Component {
	//function...
}

abstract class AdvancedComponent extends Component {
	use StandardDecoratorTrait;
}

class SpecificAdvancedComponent extends AdvancedComponent {
	//function...
}

Adesso vediamo se funziona:

new SpecificAdvancedComponent(
	new GenericComponent()
);

Ok, tutto funziona!!!

Adesso però, invece della classe Component astratta, vogliamo usare 
un'interfaccia. Quindi apportiamo queste modifiche:

interface Component {
	//function...
}

class GenericComponent implements Component {
	//function...
}

abstract class AdvancedComponent implements Component {
	use StandardDecoratorTrait;
}

Vediamo se funziona...

Fatal error: Cannot access parent:: when current class scope has no 
parent in test.php on line 3

In pratica *parent* deve essere per forza una classe...
Se è un'interfaccia, il trait non la accetta...
Soluzione?

[toc] | [next] | [standalone]


#20683

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-22 10:36 +0100
Message-ID<dnu9l4Fkjo2U1@mid.individual.net>
In reply to#20682
On 22/04/2016 10:10, alex wrote:

> In pratica *parent* deve essere per forza una classe...
> Se è un'interfaccia, il trait non la accetta...
> Soluzione?

Non cercare di implementare decoratori coi trait.

Bye.

[toc] | [prev] | [next] | [standalone]


#20684

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-22 12:08 +0200
Message-ID<nfct6l$8bg$1@gioia.aioe.org>
In reply to#20683
Il 22/04/2016 11:36, Alessandro Pellizzari ha scritto:
> On 22/04/2016 10:10, alex wrote:
>
>> In pratica *parent* deve essere per forza una classe...
>> Se è un'interfaccia, il trait non la accetta...
>> Soluzione?
>
> Non cercare di implementare decoratori coi trait.
>
> Bye.
>

lo si fa per evitare rindondanze e scrivere sempre le stesse istruzioni 
di base

trait WrapperBasicStructure {
	private $_wrapped;
	
	protected function _set($wrapped) {
		//  if (!isValid($wrapped)) throw new ...
		$this->_wrapped = $wrapped;
	}
	
	function get() {
		return $this->_wrapped;
	}
}

stavolta non ho messo il __construct per il problema di cui sopra...

[toc] | [prev] | [next] | [standalone]


#20685

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-22 14:39 +0100
Message-ID<dnunrpFo6dcU1@mid.individual.net>
In reply to#20684
On 22/04/2016 11:08, alex wrote:

> Il 22/04/2016 11:36, Alessandro Pellizzari ha scritto:

>> Non cercare di implementare decoratori coi trait.

> lo si fa per evitare rindondanze e scrivere sempre le stesse istruzioni
> di base

Le uniche due cose che un decoratore deve fare sono implemnetare 
l'inteface dell'oggetto wrappato (e non puoi farlo con un trait) e 
prendere l'oggetto wrappato nel costruttore (e diventa impossibile usare 
type-hinting o verificare se stai wrappando il tipo giusto di oggetto se 
lo metti in un trait generico).

Alias: non usare i trait per fare decoratori.

>      protected function _set($wrapped) {
>      function get() {

Un decoratore non deve avere setter e getter per l'oggetto wrappato.
Sia perchè l'interface dell'oggetto wrappato potrebbe volerli usare per 
i suoi motivi, sia perchè deve essere totalmente trasparente nell'uso, e 
permettere a chiunque di cambiare l'oggetto wrappato o di andarselo a 
prendere, è sbagliato.

E se poi hai un oggetto decorato 4 volte, per risalire all'oggetto 
originale fai ->get()->get()->get()->get() ?

Poi ognuno sceglie lo strumento più doloroso per farsi male, quindi puoi 
continuare quello che stai facendo, solo se lo rendi pubblico magari non 
chiamarlo decoratore o wrapper. :)

Bye.

[toc] | [prev] | [next] | [standalone]


#20687

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-22 16:31 +0200
Message-ID<nfdck8$156e$1@gioia.aioe.org>
In reply to#20685
Il 22/04/2016 15:39, Alessandro Pellizzari ha scritto:
> On 22/04/2016 11:08, alex wrote:
>
>> Il 22/04/2016 11:36, Alessandro Pellizzari ha scritto:
>
>>> Non cercare di implementare decoratori coi trait.
>
>> lo si fa per evitare rindondanze e scrivere sempre le stesse istruzioni
>> di base
>
> Le uniche due cose che un decoratore deve fare sono implemnetare
> l'inteface dell'oggetto wrappato (e non puoi farlo con un trait) e

Perchè no? Almeno in parte...
E se questa parte c'è l'ho già pronta (impacchettata per bene in un 
apposito trait), perchè non riutilizzarla (use MioTrait;)?

> prendere l'oggetto wrappato nel costruttore (e diventa impossibile usare
> type-hinting o verificare se stai wrappando il tipo giusto di oggetto se
> lo metti in un trait generico).
>

D'accordo.

> Alias: non usare i trait per fare decoratori.
>
>>      protected function _set($wrapped) {
>>      function get() {
>
> Un decoratore non deve avere setter e getter per l'oggetto wrappato.
> Sia perchè l'interface dell'oggetto wrappato potrebbe volerli usare per
> i suoi motivi, sia perchè deve essere totalmente trasparente nell'uso, e
> permettere a chiunque di cambiare l'oggetto wrappato o di andarselo a
> prendere, è sbagliato.
>

...????

> E se poi hai un oggetto decorato 4 volte, per risalire all'oggetto
> originale fai ->get()->get()->get()->get() ?
>

Quindi come si dovrebbe fare?

[toc] | [prev] | [next] | [standalone]


#20690

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-22 18:16 +0100
Message-ID<dnv4k9FrdduU1@mid.individual.net>
In reply to#20687
On 22/04/2016 15:31, alex wrote:

> Il 22/04/2016 15:39, Alessandro Pellizzari ha scritto:

>> Le uniche due cose che un decoratore deve fare sono implemnetare
>> l'inteface dell'oggetto wrappato (e non puoi farlo con un trait) e
>
> Perchè no? Almeno in parte...

trait T implements I { ... }
class C { use T; }

var_dump(C instanceof I); // -> false;


> E se questa parte c'è l'ho già pronta (impacchettata per bene in un
> apposito trait), perchè non riutilizzarla (use MioTrait;)?

Perchè non c'é niente da implementare in un trait.
I decoratori sono troppo specifici e minimali perchè un trait abbia senso.

>> Un decoratore non deve avere setter e getter per l'oggetto wrappato.
>> Sia perchè l'interface dell'oggetto wrappato potrebbe volerli usare per
>> i suoi motivi, sia perchè deve essere totalmente trasparente nell'uso, e
>> permettere a chiunque di cambiare l'oggetto wrappato o di andarselo a
>> prendere, è sbagliato.
>>
>
> ...????

class Log {
  protected $logs = [];
  public function set($log) { $this->logs[] = $log; }
  public function get() { return implode("\n", $this->logs; }
}

class LogDecorator {
  use TuoTrait;
}

class DecoratedLog extends LogDecorator;

$l = new DecoratedLog(new Log());

$l->set('Errore');

var_dump($l->get());

Ti aspetti che torni (string) "Errore" e invece ti torna un dump della 
classe Log.

>> E se poi hai un oggetto decorato 4 volte, per risalire all'oggetto
>> originale fai ->get()->get()->get()->get() ?
>>
>
> Quindi come si dovrebbe fare?

Non devi mai accedere all'oggetto wrappato da niente che non sia il 
decoratore stesso:

interface LoggerInterface {
  public function set($log);
  public funciton get($log);
}

class Log implements LoggerInterface
{
   protected $logs = [];
   public function set($log) { $this->logs[] = $log; }
   public function get() { return $this->logs; }
}


class HtmlLog implements LoggerInterface
{
   private $wrapped;
   public function __construct(LoggerInterface $log) {
     $this->wrapped = $log;
   }

   public function get() {
     return '<ul><li>'.
       implode('<\li><li>', $this->wrapped->get()).
       '<\li><\ul>';
   }
   public function set($log) { $this->wrapper->set($log); }
}

$htmlLogger = new HtmlLog(new Log());

var_dump($htmlLogger instanceof LoggerInterface); // -> true


Nota che il costruttore forza il parametro ad essere la stessa 
interfaccia che lui stesso implementa.

Questo coi trait non lo puoi fare.
A meno di non impazzire con le Reflection, ma ha senso, per risparmiare 
3 righe di codice?

Nota che $wrapped è privato, perchè solo HtmlLog deve poterci accedere. 
Nessun'altro sa che è un decoratore, altrimenti perdi il senso dei 
decoratori (devono essere invisibili).

Cosa ti rimane da mettere in un trait? Niente.

Bye.

[toc] | [prev] | [next] | [standalone]


#20691

Fromfmassei@gmail.com
Date2016-04-22 10:58 -0700
Message-ID<35c8155d-8ea2-4cf1-966a-926f5827e1cf@googlegroups.com>
In reply to#20690
On Friday, April 22, 2016 at 1:17:00 PM UTC-4, Alessandro Pellizzari wrote:
> <snip>
> Cosa ti rimane da mettere in un trait? Niente.
> 

Vero in generale, però dipende sempre dalla struttura che sta cercando di
tirare su..

Nell'esempio che ha messo in risposta a me ci sono due gerarchie separate di
oggetti; visto che in PHP l'ereditarietà è singola e nei concrete decorator
serve di ereditare da due diverse classi base, a meno di non ristrutturare
tutto il codice facendo derivare due classi che concettualmente non c'appizzano
nulla da una stessa classe fatta ad-hoc, una trait potrebbe far comodo.

Su uno dei commenti della documentazione ufficiale c'è penso la frase più 
sensata riguardante le trait che abbia mai letto: sono "language assisted copy
and paste" :) Usarle per strutturare gli oggetti è impossibile, ma se proprio
uno deve copia-incollare, a 'sto punto, meglio una trait :)

Ciao!


P.S.
Per esempio:

interface BaseComponent { };
interface Component1 extends BaseComponent { public function operation1(); }; 
interface Component2 extends BaseComponent { public function operation2(); }; 

trait Decorator1and2Helper {
    protected $components; /* array of BaseComponents */
    protected function addComponent(BaseComponents $c) {
        $this->components[] = $c;
    }
    protected function removeComponent(BaseComponents $c) { /* .. */ }
    protected function serializeAll() { /* .. */ }
    /* .. */
}

abstract class ComponentDecorator1 implements Component1 { 
    use DecoratorHelper;
}
abstract class ComponentDecorator2 implements Component2 { 
    use DecoratorHelper;
}

class ConcreteDecorator1a extends ComponentDecorator1 { 
    public function operation1() { foreach($this->components as $c) /*...*/ } 
}
class ConcreteDecorator1b extends ComponentDecorator1 { 
    public function operation1() { foreach($this->components as $c) /*...*/ } 
}
class ConcreteDecorator2 extends ComponentDecorator2 { 
    public function operation2() { foreach($this->components as $c) /*...*/ } 
}

[toc] | [prev] | [next] | [standalone]


#20692

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-22 20:00 +0000
Message-ID<dnve7cFtcr9U1@mid.individual.net>
In reply to#20691
Il Fri, 22 Apr 2016 10:58:41 -0700, fmassei ha scritto:

> Nell'esempio che ha messo in risposta a me ci sono due gerarchie
> separate di oggetti; visto che in PHP l'ereditarietà è singola e nei
> concrete decorator serve di ereditare da due diverse classi base, a meno
> di non ristrutturare tutto il codice facendo derivare due classi che
> concettualmente non c'appizzano nulla da una stessa classe fatta ad-hoc,
> una trait potrebbe far comodo.

Sì, ma per come l'ho capita io, lui vuole implementare la logica del 
pattern decorator dentro un trait, che non ha senso.

Certo che se due classi hanno funzioni identiche (per esempio per 
implementare ArrayAccess o Iterator in PHP) puoi fare un trait che 
implementi offsetGet, offsetSet, ecc. e usarlo in due classi che poi 
possono essere decoratori o anche decorate, ma di sicuro non puoi mettere 
il costruttore in un trait, e get/set (o, peggio, __get/__set) no. :)
 
> Su uno dei commenti della documentazione ufficiale c'è penso la frase
> più sensata riguardante le trait che abbia mai letto: sono "language
> assisted copy and paste" :) Usarle per strutturare gli oggetti è
> impossibile, ma se proprio uno deve copia-incollare, a 'sto punto,
> meglio una trait :)

Io adoro i trait, non fraintendermi.
Solo credo siano la soluzione sbagliata per implementare decoratori.

> Per esempio:

Faccio il pignainculo :) ma io questo lo considererei più un proxy verso 
componenti multipli, o un multiplexer, più che un decoratore, ma capisco 
cosa cerchi di fare e l'idea è interessante.

Ma stai implementando tramite trait le operazioni degli oggetti base, non 
la logica di decorator, che è la cosa giusta. :)

Bye.

[toc] | [prev] | [next] | [standalone]


#20696

Fromfmassei@gmail.com
Date2016-04-22 14:01 -0700
Message-ID<44f1e400-959b-4ef0-833e-f128417b7b66@googlegroups.com>
In reply to#20692
On Friday, April 22, 2016 at 4:00:46 PM UTC-4, Alessandro Pellizzari wrote:
> Il Fri, 22 Apr 2016 10:58:41 -0700, fmassei ha scritto:
> 
> > Nell'esempio che ha messo in risposta a me ci sono due gerarchie
> > separate di oggetti; visto che in PHP l'ereditarietà è singola e nei
> > concrete decorator serve di ereditare da due diverse classi base, a meno
> > di non ristrutturare tutto il codice facendo derivare due classi che
> > concettualmente non c'appizzano nulla da una stessa classe fatta ad-hoc,
> > una trait potrebbe far comodo.
> 
> Sì, ma per come l'ho capita io, lui vuole implementare la logica del 
> pattern decorator dentro un trait, che non ha senso.
> 
> Certo che se due classi hanno funzioni identiche (per esempio per 
> implementare ArrayAccess o Iterator in PHP) puoi fare un trait che 
> implementi offsetGet, offsetSet, ecc. e usarlo in due classi che poi 
> possono essere decoratori o anche decorate, ma di sicuro non puoi mettere 
> il costruttore in un trait, e get/set (o, peggio, __get/__set) no. :)
> 

Sì, certamente, speravo fosse solo un esempio e non un caso concreto :)

> > Su uno dei commenti della documentazione ufficiale c'è penso la frase
> > più sensata riguardante le trait che abbia mai letto: sono "language
> > assisted copy and paste" :) Usarle per strutturare gli oggetti è
> > impossibile, ma se proprio uno deve copia-incollare, a 'sto punto,
> > meglio una trait :)
> 
> Io adoro i trait, non fraintendermi.
> Solo credo siano la soluzione sbagliata per implementare decoratori.
> 

Io invece non li uso proprio mai :)
Non so, non sono un qualcosa che fa parte di come ragiono solitamente :)

> > Per esempio:
> 
> Faccio il pignainculo :) ma io questo lo considererei più un proxy verso 
> componenti multipli, o un multiplexer, più che un decoratore, ma capisco 
> cosa cerchi di fare e l'idea è interessante.
> 

mmm dici?
Anche se non credo molto nell'utilità dei nomi:
Non ce l'ho sottomano, ma sono abbastanza sicuro che nel GoF il decorator
è esattamente come l'ho scritto :) Sicuro si basa sul composite.
Il proxy è uguale all'adapter ma con un interfaccia in più di mezzo (e non
sono composite).

Poi di nuovo, in PHP è "tutto un po' diverso", e alla fine conta solo se il
design fa quel che deve  :)

> Ma stai implementando tramite trait le operazioni degli oggetti base, non 
> la logica di decorator, che è la cosa giusta. :)
> 

ehehe, meno male! Come ti ho detto non le uso mai, magari avevo pure scritto
'na ca**ata! ;)

Ciao!

[toc] | [prev] | [next] | [standalone]


#20702

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-23 17:56 +0000
Message-ID<do1r9tFh71hU3@mid.individual.net>
In reply to#20696
Il Fri, 22 Apr 2016 14:01:31 -0700, fmassei ha scritto:

> Anche se non credo molto nell'utilità dei nomi:
> Non ce l'ho sottomano, ma sono abbastanza sicuro che nel GoF il
> decorator è esattamente come l'ho scritto :) Sicuro si basa sul
> composite.

Sì, è così, anche se io il GoF l'ho mollato perché è uno dei libri scritti 
peggio tra quelli che ho letto. È praticamente incomprensibile per me. 
Troppo linguaggio astratto, pochi esempi, niente applicazioni concrete.
Su Wikipedia è scritto meglio, ed è tutto dire...

Non so onestamente perché non usino le Interface. Forse volevano renderlo 
più generico possibile anche per linguaggi che non le hanno.

La mia "critica" era più che altro sul decorare due oggetti 
contemporaneamente. È una cosa che non avevo mai preso in considerazione e 
dovrò esplorarla meglio. :)

> Poi di nuovo, in PHP è "tutto un po' diverso", e alla fine conta solo se
> il design fa quel che deve  :)

Poco ma sicuro.

A partire dal fatto che compile-time e run-time sono quasi la stessa cosa, 
quindi la definizione "pattern per avere a run-time comportamenti che 
altrimenti sarebbero possibili solo a compile-time" non ha molto senso.

Bye.

[toc] | [prev] | [next] | [standalone]


#20709

Fromfmassei@gmail.com
Date2016-04-24 22:16 -0700
Message-ID<d27c6537-e0a8-4ffb-9480-a2c0284932d6@googlegroups.com>
In reply to#20702
On Saturday, April 23, 2016 at 1:56:15 PM UTC-4, Alessandro Pellizzari wrote:
> Il Fri, 22 Apr 2016 14:01:31 -0700, fmassei ha scritto:
> 
> > Anche se non credo molto nell'utilità dei nomi:
> > Non ce l'ho sottomano, ma sono abbastanza sicuro che nel GoF il
> > decorator è esattamente come l'ho scritto :) Sicuro si basa sul
> > composite.
> 
> Sì, è così, anche se io il GoF l'ho mollato perché è uno dei libri scritti 
> peggio tra quelli che ho letto. È praticamente incomprensibile per me. 
> Troppo linguaggio astratto, pochi esempi, niente applicazioni concrete.
> Su Wikipedia è scritto meglio, ed è tutto dire...
> 

Veramente la pensi così? :O Io l'ho sempre considerato uno dei migliori,
specialmente per gli esempi, a dire il vero, ogni pattern ha una descrizione,
un applicazione e un'implementazione.. meglio di questo.. :)
E' vero che di pattern ce ne sono troppi e molti sono troppo simili tra loro,
tanto che alcuni sono proprio identici... ma vabbè, .5Kpagine sennò come le
riempi? :D

> Non so onestamente perché non usino le Interface. Forse volevano renderlo 
> più generico possibile anche per linguaggi che non le hanno.
> 

Certamente, è un libro sul design software, non sui linguaggi :)

> La mia "critica" era più che altro sul decorare due oggetti 
> contemporaneamente. È una cosa che non avevo mai preso in considerazione e 
> dovrò esplorarla meglio. :)
> 

Bah, per come l'ho presa io è solo un insieme di concetti che puoi applicare
come meglio credi dove meglio credi. Il libro prende in esame un applicazione
specifica (un editor di testi, se non ricordo male, come ho detto non ce l'ho
sotto mano, purtroppo) e fa vedere come usarli tutti. Poi naturalmente sta
a te prendere le idee generali e usarle, modificandole, dove vuoi :)

> > Poi di nuovo, in PHP è "tutto un po' diverso", e alla fine conta solo se
> > il design fa quel che deve  :)
> 
> Poco ma sicuro.
> 
> A partire dal fatto che compile-time e run-time sono quasi la stessa cosa, 
> quindi la definizione "pattern per avere a run-time comportamenti che 
> altrimenti sarebbero possibili solo a compile-time" non ha molto senso.
> 

Già, questo è bel punto!

Ci sono pattern famosi per linguaggi OOP compilati e per linguaggi funzionali
interpretati, e il PHP è in un posticino lì in mezzo..

Io ho risolto i miei dubbi sulle possibli architetture non leggendo una delle
milioni di vagonate di sterco che si trovano in giro, ma il codice del motore
Zend (del resto sono un programmatore c :) e, se devo dirla tutta, anche 
scrivendomi un compilatore PHP a mano da zero, nel tempo libero, ma al tempo
della 3.x, molto prima che avesse la complessità che ha ora - c'ho riprovato
a leggermi il codice qualche mese fa, con l'uscita della 7, ma a parte il
parser e tutta la parte delle primitive, ho molta difficoltà a seguire tutti i
ragionamenti senza perderci più tempo di quanto non ne abbia).

Once again: l'importante è il risultato. Se un design fa quel che deve, 
il codice sopra funziona, è comprensibile e manutenibile, allora sta a posto.

Uno studia tutto, poi usa quello che serve! :)

> Bye.

Ciao!

[toc] | [prev] | [next] | [standalone]


#20711

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-25 14:10 +0100
Message-ID<do6j9hFnnf5U1@mid.individual.net>
In reply to#20709
On 25/04/2016 06:16, fmassei@gmail.com wrote:

> On Saturday, April 23, 2016 at 1:56:15 PM UTC-4, Alessandro Pellizzari wrote:

>> Sì, è così, anche se io il GoF l'ho mollato perché è uno dei libri scritti
>> peggio tra quelli che ho letto. È praticamente incomprensibile per me.

> Veramente la pensi così? :O Io l'ho sempre considerato uno dei migliori,
> specialmente per gli esempi, a dire il vero, ogni pattern ha una descrizione,
> un applicazione e un'implementazione.. meglio di questo.. :)

Avevo provato a leggerlo 7-8 anni fa. Magari mi mancavano delle basi 
teoriche o pratiche, e per me era arabo.

O forse è perché sono allergico al linguaggio "accademico".
Per dire: un sacco di gente elogia il manuale di Rust mentre io, a parte 
le basi, lo trovo incomprensibile. :)

Credo che ognuno impari a modo suo. Io sono molto "figurativo". Se mi 
fai 3-4 esempi di come funziona capisco di più che leggendomi una 
dimostrazione matematica, mentre per altri probabilmente è il contrario.

> Uno studia tutto, poi usa quello che serve! :)

+1  :D

Bye.

[toc] | [prev] | [next] | [standalone]


#20694

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-22 22:26 +0200
Message-ID<nfe1ei$a8j$1@gioia.aioe.org>
In reply to#20691
Il 22/04/2016 19:58, fmassei@gmail.com ha scritto:
> Nell'esempio che ha messo in risposta a me ci sono due gerarchie separate di
> oggetti; visto che in PHP l'ereditarietà è singola e nei concrete decorator
> serve di ereditare da due diverse classi base, a meno di non ristrutturare
> tutto il codice facendo derivare due classi che concettualmente non c'appizzano
> nulla da una stessa classe fatta ad-hoc, una trait potrebbe far comodo.
>

Esattamente.
Quando serve (è visto che ci sono le apposite strutture) bisogna anche 
saper implementare parallelamente (in orizzontale).

> Su uno dei commenti della documentazione ufficiale c'è penso la frase più
> sensata riguardante le trait che abbia mai letto: sono "language assisted copy
> and paste":)  Usarle per strutturare gli oggetti è impossibile, ma se proprio
> uno deve copia-incollare, a 'sto punto, meglio una trait:)

Condivido

[toc] | [prev] | [next] | [standalone]


#20693

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-22 22:18 +0200
Message-ID<nfe0uj$9e3$1@gioia.aioe.org>
In reply to#20690
Il 22/04/2016 19:16, Alessandro Pellizzari ha scritto:
> On 22/04/2016 15:31, alex wrote:
>
>> Il 22/04/2016 15:39, Alessandro Pellizzari ha scritto:
>
>>> Le uniche due cose che un decoratore deve fare sono implemnetare
>>> l'inteface dell'oggetto wrappato (e non puoi farlo con un trait) e
>>
>> Perchè no? Almeno in parte...
>
> trait T implements I { ... }
> class C { use T; }
>
> var_dump(C instanceof I); // -> false;
>

Qui hai cambiato un po' le cose, cmq a me dà


Fatal error: Cannot use 'I' as interface on 'T' since it is a Trait

>
>> E se questa parte c'è l'ho già pronta (impacchettata per bene in un
>> apposito trait), perchè non riutilizzarla (use MioTrait;)?
>
> Perchè non c'é niente da implementare in un trait.
> I decoratori sono troppo specifici e minimali perchè un trait abbia senso.
>

Forse nella maggior parte dei casi, tuttavia, comme ho fatto intuire, 
tutto può essere relativo.

>>> Un decoratore non deve avere setter e getter per l'oggetto wrappato.
>>> Sia perchè l'interface dell'oggetto wrappato potrebbe volerli usare per
>>> i suoi motivi, sia perchè deve essere totalmente trasparente nell'uso, e
>>> permettere a chiunque di cambiare l'oggetto wrappato o di andarselo a
>>> prendere,

Allora forse volevi dire "e NON permettere a chiunque...".

> è sbagliato.

E' sbagliaro che cosa?
Forse volevi dire "(è una pratica sbaglata)" con le opportune parentesi.

> class Log {
>   protected $logs = [];
>   public function set($log) { $this->logs[] = $log; }
>   public function get() { return implode("\n", $this->logs; }
> }
>
> class LogDecorator {
>   use TuoTrait;
> }
>
> class DecoratedLog extends LogDecorator;
>
> $l = new DecoratedLog(new Log());
>
> $l->set('Errore');
>
> var_dump($l->get());
>
> Ti aspetti che torni (string) "Errore" e invece ti torna un dump della
> classe Log.
>

Ad ogni modo, qui hai ragione :P

>>> E se poi hai un oggetto decorato 4 volte, per risalire all'oggetto
>>> originale fai ->get()->get()->get()->get() ?
>>>
>>
>> Quindi come si dovrebbe fare?
>
> Non devi mai accedere all'oggetto wrappato da niente che non sia il
> decoratore stesso:
>

OK

> interface LoggerInterface {
>   public function set($log);
>   public funciton get($log);
> }
>
> class Log implements LoggerInterface
> {
>    protected $logs = [];
>    public function set($log) { $this->logs[] = $log; }
>    public function get() { return $this->logs; }
> }
>
>
> class HtmlLog implements LoggerInterface
> {
>    private $wrapped;
>    public function __construct(LoggerInterface $log) {
>      $this->wrapped = $log;
>    }
>
>    public function get() {
>      return '<ul><li>'.
>        implode('<\li><li>', $this->wrapped->get()).
>        '<\li><\ul>';
>    }
>    public function set($log) { $this->wrapper->set($log); }
> }

Io però avrei fatto così:

abstract class LoggerInterface {
  protected $logs = [];

  // todo: questa funzione sarebbe meglio chiamarla add
  final function set($log)
  {
    $this->logs[] = $log; // aggiunge un logger
  }

  abstract funciton get($log);
}

class Log implements LoggerInterface
{
   public function get() { return $this->logs; }
}


class HtmlLog implements LoggerInterface
{
   private $wrapped;

   public function __construct(LoggerInterface $log) {
     $this->wrapped = $log;
   }

   public function get() {
     return '<ul><li>'.
       implode('<\li><li>', $this->wrapped->get()).
       '<\li><\ul>';
   }
}


>
> $htmlLogger = new HtmlLog(new Log());
>
> var_dump($htmlLogger instanceof LoggerInterface); // -> true
>

Certo :P


>
> Nota che il costruttore forza il parametro ad essere la stessa
> interfaccia che lui stesso implementa.
>

Certamente

[toc] | [prev] | [next] | [standalone]


#20695

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-22 20:46 +0000
Message-ID<dnvgthFtcr9U2@mid.individual.net>
In reply to#20693
Il Fri, 22 Apr 2016 22:18:27 +0200, alex ha scritto:

>>>> Un decoratore non deve avere setter e getter per l'oggetto wrappato.
>>>> Sia perchè l'interface dell'oggetto wrappato potrebbe volerli usare
>>>> per i suoi motivi, sia perchè deve essere totalmente trasparente
>>>> nell'uso, e permettere a chiunque di cambiare l'oggetto wrappato o di
>>>> andarselo a prendere,
> 
> Allora forse volevi dire "e NON permettere a chiunque...".
> 
>> è sbagliato.

Ho sbagliato a mettere la virgola:

Sia perchè l'interface dell'oggetto wrappato potrebbe volerli usare
per i suoi motivi, sia perchè deve essere totalmente trasparente
nell'uso. E permettere a chiunque di cambiare l'oggetto wrappato o di
andarselo a prendere è sbagliato.

> Io però avrei fatto così:
> 
> abstract class LoggerInterface {
>   protected $logs = [];
> 
>   // todo: questa funzione sarebbe meglio chiamarla add final function
>   set($log)
>   {
>     $this->logs[] = $log; // aggiunge un logger
>   }
> 
>   abstract funciton get($log);
> }
> 
> class Log implements LoggerInterface {
>    public function get() { return $this->logs; }
> }
> 
> 
> class HtmlLog implements LoggerInterface {
>    private $wrapped;
> 
>    public function __construct(LoggerInterface $log) {
>      $this->wrapped = $log;
>    }
> 
>    public function get() {
>      return '<ul><li>'.
>        implode('<\li><li>', $this->wrapped->get()).
>        '<\li><\ul>';
>    }
> }

Il problema è che così non funziona. :)

HtmlLog, ereditando da LoggerInterface sia lo storage che il setter, salva 
i log nel suo spazio (la sua $this->logs) e non in quello dell'oggetto 
wrappato ($this->wrapped->logs), ma la sua get va a prenderli nell'oggetto 
decorato, quindi saranno sempre vuoti.

Per questo non conviene che un decorator extend-a una classe abstract, ma 
è meglio che implement-i un'interface. In questo modo non hai zavorra con 
rischi, come in questo caso, di dimenticarti di wrappare una funzione e 
spaccare tutto.
 
Bye.

[toc] | [prev] | [next] | [standalone]


#20697

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-23 10:30 +0200
Message-ID<nffbqp$1u9k$1@gioia.aioe.org>
In reply to#20695
Il 22/04/2016 22:46, Alessandro Pellizzari ha scritto:
> Il problema è che così non funziona.:)
>
> HtmlLog, ereditando da LoggerInterface sia lo storage che il setter, salva
> i log nel suo spazio (la sua $this->logs) e non in quello dell'oggetto
> wrappato ($this->wrapped->logs), ma la sua get va a prenderli nell'oggetto
> decorato, quindi saranno sempre vuoti.
>
> Per questo non conviene che un decorator extend-a una classe abstract, ma
> è meglio che implement-i un'interface. In questo modo non hai zavorra con
> rischi, come in questo caso, di dimenticarti di wrappare una funzione e
> spaccare tutto.
>

Vero. Ma a questo punto userei la cara vecchia ereditarietà

interface LoggerInterface
{
  function get($key);
}

class Log implements LoggerInterface
{
  private $logs = [];

  // todo: questa funzione sarebbe meglio chiamarla add
  final function set($log)
  {
    $this->logs[] = $log; // aggiunge un logger
  }

  function get($key) { return $this->logs[$key]; }
}

class HtmlLog extends Log
{
   function get($key) {
     return '<ul><li>'.
       implode('<\li><li>', parent::get($key)).
       '<\li><\ul>';
   }
}



Lo dico perchè implementare roba inutile come questa

function set($log)// a cosa serve questa funzione? ad appesantire...
{
  $this->wrapper->set($log);
}

non me la sento!

[toc] | [prev] | [next] | [standalone]


#20698

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-23 11:07 +0200
Message-ID<nffe1g$265$1@gioia.aioe.org>
In reply to#20697
Il 23/04/2016 10:30, alex ha scritto:
>
> interface LoggerInterface
> {
>   function get($key);
> }
>
> class Log implements LoggerInterface
> {
>   private $logs = [];
>
>   // todo: questa funzione sarebbe meglio chiamarla add
>   final function set($log)
>   {
>     $this->logs[] = $log; // aggiunge un logger
>   }
>
>   function get($key) { return $this->logs[$key]; }
> }
>
> class HtmlLog extends Log
> {
>    function get($key) {
>      return '<ul><li>'.
>        implode('<\li><li>', parent::get($key)).
>        '<\li><\ul>';
>    }
> }
>
>

Ancora meglio

class Logs
{
	private $logs = [];

	final function add($log)
	{
		$this->logs[] = $log;
	}
	
	final function get($key) {
		return $this->logs[$key];
	}
}

class HtmlLog
{
	private $wrapped;
	
	function __construct($wrapped)
	{
		$this->wrapped=
				'<ul><li>'.
				$wrapped.
				'<\li><\ul>'
		;
	}
	
	function __toString()
	{
		return $this->wrapped;
	}
}

$logs = new Logs();
$log->add(new HtmlLog(123));

[toc] | [prev] | [next] | [standalone]


#20699

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-23 11:32 +0200
Message-ID<nfffg3$4e4$1@gioia.aioe.org>
In reply to#20698
Il 23/04/2016 11:07, alex ha scritto:
>
> $logs = new Logs();
> $log->add(new HtmlLog(123));

E si potrebbe buttare (se non serve) anche la classe Logs.

$logs[] = new HtmlLog(123);

[toc] | [prev] | [next] | [standalone]


#20701

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2016-04-23 17:50 +0000
Message-ID<do1qvaFh71hU2@mid.individual.net>
In reply to#20698
Il Sat, 23 Apr 2016 11:07:58 +0200, alex ha scritto:

> $log = new Logs();
> $log->add(new HtmlLog(123));

Qui non stai decorando. Stai scrivendo dati "sporchi" dentro $log.
Per sporchi intendo non omogenei, perché puoi infilarci HTML, testo, 
immagini, ecc.

Magari è quello che vuoi, eh. Non discuto, ma converrai con me che non è 
né trasparente (chi scrive il log deve sapere cosa sta scrivendo) né pulito 
(come distingui i dati in estrazione?).

Questo può avvicinarsi a uno strategy pattern se nella variabile 
$log->logs salvi l'oggetto HtmlLog, invece di una stringa generica. In 
questo modo in fase di estrazione sai cos'è (un oggetto HtmlLog) e puoi 
decidere una strategia per visualizzarlo.

Bye.

[toc] | [prev] | [next] | [standalone]


#20704

Fromalex <1j9448a02@lnx159sneakemail.com.invalid>
Date2016-04-24 10:36 +0200
Message-ID<nfi0ja$1i9b$1@gioia.aioe.org>
In reply to#20701
Il 23/04/2016 19:50, Alessandro Pellizzari ha scritto:
> Il Sat, 23 Apr 2016 11:07:58 +0200, alex ha scritto:
>
>> $log = new Logs();
>> $log->add(new HtmlLog(123));
>
> Qui non stai decorando. Stai scrivendo dati "sporchi" dentro $log.
> Per sporchi intendo non omogenei, perché puoi infilarci HTML, testo,
> immagini, ecc.
>

Vero.
Ma se ho il pieno controllo di quello che sto facendo potrebbe anche 
andar bene.

> Magari è quello che vuoi, eh. Non discuto, ma converrai con me che non è
> né trasparente (chi scrive il log deve sapere cosa sta scrivendo) né pulito
> (come distingui i dati in estrazione?).
>

$textLogs = new Logs;
$htmlLogs = new Logs;

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | it.comp.www.php


csiph-web