------------------------------------------------------------------------------ Some patterns I find useful when developing in Liberty Eiffel. These patterns nicely complement the standard GoF patterns. ------------------------------------------------------------------------------ Typed Derivation ================ Pattern: -------- deferred class NON_TYPED ... end class TYPED[E_] inherit NON_TYPED ... end Usage: ------ When you need to keep mixed up data whose type is not known in advance. The non_typed base class is used to present a common non-typed interface and move the data around, the typed class is used to access the data itself. This pattern is really useful to enforce strong typing. See also: --------- A companion pattern is the Agent-based Generics Visitor (see below). Examples: --------- * SmartEiffel's INTERNALS * Liberty's interpreter: objects, builtins ------------------------------------------------------------------------------ Agent-based Visitor =================== (the non-generics one) Pattern: -------- class ITEM feature {ANY} accept (v: VISITOR) do visitor.call([v, Current]) end feature {} visitor: PROCEDURE[TUPLE[VISITOR, ITEM]] ... end class FACTORY feature {ANY} new_item_1: SOMETHING do create Result.make(agent {VISITOR}.visit_1) end new_item_2: SOMETHING do create Result.make(agent {VISITOR}.visit_2) end ... end deferred class VISITOR feature {ANY} visit_1 (i: ITEM) is deferred end visit_2 (i: ITEM) is deferred end ... end Usage: ------ Some objects share a common base type, but we need to distinguish some instances with a special role. For some reason we want the objects to share the same runtime type. This kind of visitor helps differentiating instances. The agent is registered at the creation of ITEM and depends on the object itself. These objects should be immutable (at least conceptually; their creation cycle may be complex). Note: usually the "agent {VISITOR}.visit_xx" is encapsulated in a once feature, to avoid the creation of too many objects. That's one reason why the visitor itself is given as target of the call. The other reason is of course to allow visitor polymorphism. The deferred visitor is defined as usual. See also: --------- Factory, to create the objects and give them an agent. Examples: --------- * Liberty's actual type visitor, an agent is given at creation time that depends on the actual instance of LIBERTY_ACTUAL_TYPE. * Liberty's "feature accelerator" is also the same pattern. * In fact the whole Liberty interpreter is built as an application of this pattern. ------------------------------------------------------------------------------ Agent-based Generics Visitor ============================ Pattern: -------- deferred class ITEM feature {ANY} accept (v: VISITOR) deferred end end class TYPED_ITEM[E_] inherit ITEM feature {ANY} item: E_ accept (v: VISITOR) do visitor.call([v, Current]) end feature {} visitor: PROCEDURE[TUPLE[VISITOR, E_]] ... end class FACTORY feature {ANY} new_item_a (a: A): ITEM do create {TYPED_ITEM[A]} Result.make(a, agent {VISITOR}.visit_a) end new_item_b (b: B): ITEM do create {TYPED_ITEM[B]} Result.make(b, agent {VISITOR}.visit_b) end ... end deferred class VISITOR feature {ANY} visit_a (i: TYPED_ITEM[A]) deferred end visit_b (i: TYPED_ITEM[B]) deferred end ... end Usage: ------ A simple application of the Agent-based Visitor to Typed Derivation. That kind of visitor helps getting access to the data of a Typed Derivation. The agent is registered at the creation of TYPED_ITEM[E_] and depends on E_ itself. See also: --------- Factory, to create typed objects and give them an agent. ------------------------------------------------------------------------------ Acyclic Visitor =============== http://www.objectmentor.com/resources/articles/acv.pdf ------------------------------------------------------------------------------ Root class creation =================== The pattern I usually use is a creation procedure that is not exported either by 'feature' or by 'create': class ROOT create {} make feature {} make do -- The program starts here... end end ------------------------------------------------------------------------------