There's a sort of pattern that I've sort of stumbled myself into "discovering" that seems extremely useful, but I've never seen it described before. It's sort of a way of achieving inheritance through an interface. It's really wierd where the class "becomes" the thing that it accepts. (Written here in C# but it doesn't have to be.)
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;
}
}
A more realistic example that is similar to what I really use:
interface IControlContainer {
Control Control { get; }
}
public class FancyControl : IControlContainer {
public Control Control { get; }
public FancyControl() {
Control = BuildControl().Control;
}
}
BuildControl()
is really code that builds an object from a script. The object is any one of many other IControlContainer
objects that are designed to build controls using certain patterns (like table layout).
Notice how the outer object effectively "becomes" the inner object. Lately I've been thinking that it almost reminds me of prototypal inheritance in JavaScript, but I'm not sure. I would love to read more about this and find other ways of applying it, but I don't think I've ever seen it before and I can't find anything about it.
I know it isn't the Composite pattern, because that's about making a hierarchy/tree of objects.
I know it isn't just straight composition, because the point here is that to an outsider, there's no difference between the inner and outer objects (when viewed as IContainer
s), yet they do actually differ and have different implementations.
Here's an even more concrete example:
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
Notice how EmployeeControl
"IS" a TableLayoutHelper
, at least when looked at as an IControlContainer
. The TLH itself can also place IControlContainer
s in it's table structure. And you can compose new IControlContainer
s out of existing ones, like I can place an EmployeeControl
onto another IControlContainer
somewhere else, and so on...
I've used an analogous system in a reporting framework as well and it works wonders.
BuildAnotherContainer()
?Control.Title = "Fancy " + Control.Title;
, then we might be looking at a Decorator pattern.BuildAnotherContainer()
is just any code that gets another one from somewhere else.