Sto sviluppando un parser BNF in PHP, per il mio gusto di BNF. Per mantenere l'albero di analisi risultante, costituito da oggetti, il più leggero possibile, ho deciso di utilizzare il modello di peso mosca per i letterali (terminali):
class Literal
{
private static $cache = array();
private $string = '';
// private constructor for flyweight pattern
private function __construct( $string ) {
$this->setString( $string );
}
// flyweight pattern
public static function fromString( $string ) {
if( !isset( self::$cache[ $string ] ) ) {
self::$cache[ $string ] = new Literal( $string );
}
return self::$cache[ $string ];
}
public function match( SourceInterface $source ) {
/* algorithm to match source against $this->string */
}
/* ... */
}
I letterali sono indicati come stringhe tra virgolette (singole o doppie), ad esempio "A"
o 'A'
.
Il mio aroma di BNF, tuttavia, supporterà anche rappresentazioni codificate di letterali a singolo carattere, denotate da un segno di percentuale e un simbolo di demarcazione decimale o esadecimale seguito da un valore, ad esempio: %d48
o %x30
.
Per implementarlo, preferirei estendere la classe Literal
, ereditando alcune delle funzionalità di Literal
, come il suo metodo match
, perché in definitiva EncodedLiteral
rappresenta la stringa Literal
, che la sorgente di input verrà confrontata.
Quindi, quello con cui giocavo era qualcosa del genere, ma poiché il costruttore di Literal
doveva essere mantenuto private
per il modello di peso mosca, mi sono confuso con cosa fare all'interno del EncodedLiteral
costruttore.
class EncodedLiteral
extends Literal
{
private static $cache = array();
private $encodedString;
// private constructor for its own flyweight pattern
private function __construct( $encodedString ) {
// this won't work, since parent::__construct() is private
// and it would bypass the flyweight pattern if it was protected
parent::__construct( $this->decodeEncodedString( $encodedString ) );
// ... and this doesn't make sense, since it would become composition
// losing the inherited functionality
$this->literal = Literal::fromString( $this->decodeEncodedString( $encodedString ) );
}
// flyweight pattern
public static function fromString( $encodedString ) {
if( !isset( self::$cache[ $encodedString ] ) ) {
self::$cache[ $encodedString ] = new EncodedLiteral( $encodedString );
}
return self::$cache[ $encodedString ];
}
private function decodeEncodedString( $encodedString ) {
/* implementation */
}
/* ... */
}
Quindi, come puoi vedere, sono un po 'bloccato qui.
C'è un modo per risolvere questo, in modo elegante, senza perdere i vantaggi del peso piuma? È questo un caso di scegliere la composizione sull'eredità, forse? Dovrei andare con il modello decoratore? Ho il terrore di dover proxy per i metodi che altrimenti erediterei con estendere Literal
, però.