Changes between Version 3 and Version 4 of TracDev/ComponentArchitecture
- Timestamp:
- Jun 22, 2006, 11:06:12 AM (18 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
TracDev/ComponentArchitecture
v3 v4 17 17 == Public classes == 18 18 19 {{{trac.core.ComponentManager}}}[[BR]]19 `trac.core.ComponentManager` [[BR]] 20 20 Manages component life cycle, instantiating registered components on demand 21 21 22 {{{trac.core.Component}}}[[BR]]22 `trac.core.Component` [[BR]] 23 23 Abstract base class for components. 24 24 25 {{{trac.core.ExtensionPoint}}}[[BR]]25 `trac.core.ExtensionPoint` [[BR]] 26 26 Declares an extension point on a component that other components can plug in to. 27 27 28 {{{trac.core.Interface}}}[[BR]]29 Every extension point specifies the contract that extenders must conform to via an {{{Interface}}}subclass.28 `trac.core.Interface` [[BR]] 29 Every extension point specifies the contract that extenders must conform to via an `Interface` subclass. 30 30 31 31 [[Image(comparch.png)]] … … 33 33 == Declaring a component == 34 34 35 The simplest possible component is an empty class derived from {{{trac.core.Component}}}:35 The simplest possible component is an empty class derived from `trac.core.Component`: 36 36 37 37 {{{ … … 49 49 }}} 50 50 51 Remember that components follow the singleton pattern. There is only one active instance of any component per component manager. The component constructor is "magic" in that it checks with the component manager whether there's already an active instance before allocating a new instance. If the component was already instantiated, the existing instance is returned:51 Remember that components follow the singleton pattern. There is only one active instance of any component per component manager. The component constructor is “magic” in that it checks with the component manager whether there´s already an active instance before allocating a new instance. If the component was already instantiated, the existing instance is returned: 52 52 53 53 {{{ … … 57 57 }}} 58 58 59 If a component needs to initialize data members, it can override the {{{__init__}}} method. But because the component manager needs to be able to instantiate the component on demand, {{{__init__}}}must ''not'' require any extra parameters, ''including'' the reference to the component manager passed into the constructor:59 If a component needs to initialize data members, it can override the `__init__` method. But because the component manager needs to be able to instantiate the component on demand, `__init__` must ''not'' require any extra parameters, ''including'' the reference to the component manager passed into the constructor: 60 60 61 61 {{{ … … 70 70 }}} 71 71 72 Direct {{{Component}}} sub-classes also do not need to worry about invoking the base classes {{{__init__}}}method (which is empty).72 Direct `Component` sub-classes also do not need to worry about invoking the base classes `__init__` method (which is empty). 73 73 74 74 == Declaring an extension point == … … 98 98 }}} 99 99 100 Here, the {{{TodoList}}} class declares an extension point called {{{observers}}} with the interface {{{ITodoObserver}}}. The interface defines the ''contract'' that extending components need to conform to.100 Here, the `TodoList` class declares an extension point called `observers` with the interface `ITodoObserver`. The interface defines the ''contract'' that extending components need to conform to. 101 101 102 The {{{TodoList}}} component notifies the observers inside the {{{add()}}} method by iterating over {{{self.observers}}} and calling the {{{todo_added()}}} method for each. The {{{Component}}} class performs some magic to enable that: Conceptually, it intercepts access to the extension point attribute andfinds all registered components that declare to extend the extension point. For each of those components, it gets the instance from the component manager, potentially activating it if it is getting accessed for the first time.102 The `TodoList` component notifies the observers inside the `add()` method by iterating over `self.observers` and calling the `todo_added()` method for each. This works because the `observers` attribute is a [http://users.rcn.com/python/download/Descriptor.htm descriptor]: When it is accessed, it finds all registered components that declare to extend the extension point. For each of those components, it gets the instance from the component manager, potentially activating it if it is getting accessed for the first time. 103 103 104 104 == Plugging in to an extension point == … … 115 115 }}} 116 116 117 This class {{{implements}}} the {{{ITodoObserver}}} interface declared above, and simply prints every new to-do item to the console. By declaring to implement the interface, it transparently registers itself as an extension of the {{{TodoList}}}class.117 This class `implements` the `ITodoObserver` interface declared above, and simply prints every new to-do item to the console. By declaring to implement the interface, it transparently registers itself as an extension of the `TodoList` class. 118 118 119 ''Note that you don't actually derivethe component from the interface it implements. That is because conformance to an interface is orthogonal to inheritance; and because Python doesn't have static typing, there's no need to explicitly mark the component as implementing an interface.''119 ''Note that you don't actually '''derive''' the component from the interface it implements. That is because conformance to an interface is orthogonal to inheritance; and because Python doesn't have static typing, there's no need to explicitly mark the component as implementing an interface.'' 120 120 121 You can specify multiple extension point interfaces to extend with the {{{implements}}}method by simply passing them as additional arguments.121 You can specify multiple extension point interfaces to extend with the `implements` method by simply passing them as additional arguments. 122 122 123 123 == Putting it together == … … 144 144 }}} 145 145 146 This output obviously comes from the {{{TodoPrinter}}}. Note however that the code snippet above doesn't even mention that class. All that is needed to have it participating in the action is to declare the class. ''(That implies that an extending class needs to be imported by a python script to be registered. The aspect of loading components is however separate from the extension mechanism itself.)''146 This output obviously comes from the `TodoPrinter`. Note however that the code snippet above doesn't even mention that class. All that is needed to have it participating in the action is to declare the class. ''(That implies that an extending class needs to be imported by a python script to be registered. The aspect of loading components is however separate from the extension mechanism itself.)'' 147 147 148 148 ----