C'è una sorta di schema in cui mi sono imbattuto in "scoprire" che sembra estremamente utile, ma non l'ho mai visto prima. È una specie di modo per ottenere l'ereditarietà attraverso un'interfaccia. È davvero strano dove la classe "diventa" ciò che accetta. (Scritto qui in C # ma non deve essere.)
interface IContainer {
Thing Thing { get; }
}
class Concrete : IContainer {
public Thing Thing { get; }
public Concrete(IContainer container) {
Thing = container.Thing;
}
// or...
public Concrete() {
Thing = BuildAnotherContainer().Thing;
}
}
Un esempio più realistico che è simile a quello che uso veramente:
interface IControlContainer {
Control Control { get; }
}
public class FancyControl : IControlContainer {
public Control Control { get; }
public FancyControl() {
Control = BuildControl().Control;
}
}
BuildControl()
è veramente un codice che costruisce un oggetto da uno script. L'oggetto è uno dei molti altri oggetti IControlContainer
progettati per creare controlli utilizzando determinati modelli (come il layout di una tabella).
Si noti come l'oggetto esterno "diventa" effettivamente l'oggetto interno. Ultimamente ho pensato che mi ricordasse quasi l'eredità prototipale in JavaScript, ma non ne sono sicuro. Mi piacerebbe leggere di più su questo e trovare altri modi per applicarlo, ma non penso di averlo mai visto prima e non riesco a trovare nulla al riguardo.
So che non è il pattern Composite, perché si tratta di creare una gerarchia / un albero di oggetti.
So che non è solo una composizione lineare, perché il punto qui è che per un estraneo, non c'è differenza tra gli oggetti interni ed esterni (se visualizzati come IContainer
s), ma in realtà differiscono e hanno differenze implementazioni.
Ecco un esempio ancora più concreto:
interface IControlContainer {
Control UntypedControl { get; }
}
interface IControlContainer<TControl> : IControlContainer
where TControl : Control {
TControl Control { get; }
}
class TableLayoutHelper : IControlContainer<TableLayoutPanel> {
public Control UntypedControl => Control;
public TableLayoutPanel Control { get; }
public TableLayoutHelper() {
Control = new TableLayoutPanel { Size = new Size(500, 500) };
}
// lots of code that makes building a UI with a table layout nice and easy
}
class EmployeeControl : IControlContainer {
public Control UntypedControl { get; }
public TextBox NameBox { get; }
public EmployeeControl() {
var tlh = new TableLayoutHelper();
// use tlh to build a table layout
NameBox = tlh.AddTextBox("Name");
UntypedControl = tlh.UntypedControl;
}
}
class ControlContainerForm : Form {
// a windows form that can host any IControlContainer
}
// then compose a ControlContainerForm with a new EmployeeControl
Nota come EmployeeControl
"IS" a TableLayoutHelper
, almeno se considerato come IControlContainer
. Lo stesso TLH può anche posizionare IControlContainer
s nella sua struttura tabellare. E puoi comporre nuovi IControlContainer
s su quelli esistenti, come posso mettere un EmployeeControl
su un altro IControlContainer
da qualche altra parte, e così via ...
Ho usato un sistema analogo anche in un quadro di reporting e fa miracoli.