Qualunque linguaggio di programmazione orientato agli oggetti supporta "costruttori collettivi"?

8

Recentemente stavo considerando che a volte diversi oggetti dipendono l'uno dall'altro (ad esempio se contengono riferimenti ciclici) e quindi sarebbe utile crearli come parte di un'operazione atomica che assicura che, dopo la costruzione, i nuovi oggetti soddisfino qualche vincolo collettivo.

Per fare ciò si possono avere costruttori che possono creare più di un oggetto. Il programmatore inserirà quindi in un singolo costruttore tutto il codice assicurando che, una volta creati gli oggetti o 1 , ..., o n , soddisfino tutti i vincoli richiesti ( ad es. tutti i collegamenti tra i nuovi oggetti sono già a posto). Ho inventato il termine costruttori collettivi me stesso perché non ho mai sentito parlare di una simile funzionalità, ma potrebbe esistere un nome accettato per questo concetto.

Quindi, esiste un linguaggio di programmazione che supporti questo tipo di costruttori? Se no, l'idea è già stata provata?

    
posta Giorgio 13.01.2014 - 22:53
fonte

3 risposte

12

Questo mi sembra il Builder Pattern per me, che è una forma più complessa di una fabbrica. Un esempio Java è un StringBuilder , che si utilizza per creare un String, quindi chiama builder.toString() quando vuoi il risultato immutabile. Tuttavia, è possibile utilizzare il modello di builder per creare raccolte di oggetti non omogenee più complesse. Puoi usare friend semantica in un builder per ottenere l'accesso a variabili private che sarebbero considerate immutabili dopo la creazione dell'oggetto risultato.

Le lingue funzionali potrebbero fornire qualche ispirazione. Scala, ad esempio, ha un ListBuffer mutabile che può essere utilizzato per fase di costruzione, quindi convertita in un Elenco .

Un altro concetto probabilmente pertinente è Oggetti Freezable , di quale oggetto è considerato mutabile fino a quando non viene chiamato un metodo Freeze() . Un costruttore può utilizzare gli oggetti non congelati, quindi bloccarli prima di tornare.

    
risposta data 13.01.2014 - 23:55
fonte
4

Ruby, Smalltalk, Self, Newspeak ecc. non hanno costruttori, hanno solo una convenzione di denominazione per i metodi factory (ad esempio new in Ruby). Dato che sono solo metodi standard come qualsiasi altro metodo, possono fare tutto ciò che vogliono, incluso allocare e inizializzare tutti gli oggetti che vogliono. Il problema principale è che tali metodi di fabbrica restituiscono, per convenzione, un singolo oggetto che è un'istanza della classe su cui è stato chiamato il metodo factory. Cioè quando si chiama Foo.new ci si aspetta che si recuperi un singolo oggetto che è un'istanza di Foo . Tuttavia, con una documentazione sufficiente, puoi restituire una struttura (ad esempio Array ) di più nuovi oggetti.

Esempio:

class Foo
  def self.new
    new_foo = super

    new_bar = Bar.new
    new_bar.foo = new_foo

    new_foo.bar = new_bar

    return new_foo, new_bar
  end

  attr_accessor :bar
end

class Bar
  attr_accessor :foo
end

foo, bar = Foo.new

In ECMAScript, i costruttori sono solo procedure regolari, o meglio, qualsiasi procedura può essere usata come costruttore semplicemente attaccando la parola chiave new di fronte ad essa. Di nuovo, dal momento che sono solo procedure regolari, possono fare tutto ciò che vogliono.

    
risposta data 13.01.2014 - 23:07
fonte
1

(e.g. if they contain cyclic references) [...] In order to do this one could have constructors that can create more than one object. The programmer would then put in a single constructor all the code ensuring that, once objects o1, ..., on have been created,

Dipendenze cicliche tra gli oggetti? Quindi la risposta è "non usare (solo) un costruttore", perché le chiamate al metodo ciclico non hanno alcun senso. Invece, questo è uno scenario classico per alcuni metodo di fabbrica s.

Ecco un esempio (in PHP) che è un po 'sciocco, ma illustra l'idea generale: non è possibile creare un Sprocket senza un Widget associato e viceversa. Ogni oggetto ha un riferimento all'altro quando diventa disponibile.

class Widget {            
    protected $sprocket = null;
    public function getSprocket(){ return $this->sprocket; }

    protected function __construct(){ 
        // Constructor cannot be called from outside, not public
        // Initialize self, to a limited degree
    }
    public static function create(Sprocket $partner=null){
        $me = new Widget(); // Can call constructor from same class

        // Here we can make all sorts of changes and additions and other
        // objects, wiring them all together, before revealing the result
        // to the outside world.

        if($partner !== null){
            $me->sprocket = $partner;

        }else{
            $me->sprocket = Sprocket::create($me);
        }
        return $me;
    }

}

/* 
 * Practically identical to Widget, just with some renaming
 */
class Sprocket {
    protected $widget = null;
    public function getWidget(){ return $this->widget; }

    protected function __construct(){  }
    public static function create(Widget $partner=null){            
        $me = new Sprocket();            
        if($partner !== null){
            $me->widget = $partner;
        }else{
            $me->widget = Widget::create($me);
        }
        return $me;
    }        
}

/* 
$mw = new Widget(); // NOT ALLOWED! Constructor not public
*/

$w = Widget::create(); // OK to call
$s = $w->getSprocket();
$w2 = $s->getWidget();

assert($w == $w2);

Se dovessi farlo in PHP 5.2 nella vita reale, dovrei semplicemente lasciare pubblici i costruttori e dire alla gente di non usarli . Invece avrei una funzione makeWidgetWithSprocket() . Se la lingua fosse Java, userei i suoi controlli di visibilità a livello di pacchetto per prevenire ulteriormente gli errori.

Letture aggiuntive:

  • Se vuoi passare molte opzioni e impostazioni a create() , considera il pattern Builder .
  • Se ti trovi a dover avere un sacco di flessibilità per ricablare le cose in modi diversi, guarda i Inversion of Control frameworks, che comunemente (ma non sempre) usa iniezione di dipendenza per connettere gli oggetti insieme "dall'esterno".
risposta data 14.01.2014 - 01:47
fonte

Leggi altre domande sui tag