1 /** 2 Aedi, a dependency injection library. 3 4 Aedi is a dependency injection library. It does provide a set of containers that do 5 IoC, and an interface to configure application components (structs, objects, etc.) 6 7 Aim: 8 9 The aim of library is to provide a dependency injection solution that is 10 feature rich, easy to use, easy to learn, and easy to extend up to your needs. 11 12 Usage: 13 14 This tutorial will show how to register a component with custom identity in container, and 15 how to reference components with custom identities. The tutorial is based on car 16 simulation presented in previous example, and will continue to improve it. 17 18 Except of a single implementation of a component, in some occurrences of an application, 19 multiple instances of same type of component, but with varying dependencies, are required. In case 20 of car simulation application, the simulator should not be limited to only a single car, it should be 21 able to have multiple cars with varying parameters, like cars of sedan or smart sizes with blue and 22 green colors. 23 24 Previous section showed how to register only one version for each component including the car 25 itself. Attempting to add another car to container like in example below, will fail due to simple problem: 26 Both cars are identified in container by their type. 27 28 ----------------- 29 register!Car 30 .construct(lref!Size) 31 .set!"color"(lref!Color); 32 33 register!Car 34 .construct(lref!Size) 35 .set!"color"(Color(0, 0, 0)); 36 ----------------- 37 38 Running in modified container configuration in context of previous tutorial's example will end 39 in output from below, were last registered instance of Car component overrides the previously 40 defined. 41 42 ----------------- 43 You bought a new car with following specs: 44 Size: Size(200, 150, 500) 45 Color: Color(0, 0, 0) 46 ----------------- 47 48 Each registered component in a container is associated with an identity in it. In case with 49 car for previous examples, the Car component is associated with identity representing it’s Type. To 50 avoid associating a component by it’s type during registration, pass it’s identity as an argument to 51 $(D_INLINECODE register) method, like in example below. A component can also be associated with an interface it 52 implements by inserting desired interface before the type of registered component. 53 54 ----------------- 55 with (container.configure) { 56 register!Color("color.green") // Register "green" color into container. 57 .set!"r"(cast(ubyte) 0) 58 .set!"g"(cast(ubyte) 255) 59 .set!"b"(cast(ubyte) 0); 60 61 register!Color("color.blue") // Register "blue" color into container. 62 .set!"r"(cast(ubyte) 0) 63 .set!"g"(cast(ubyte) 0) 64 .set!"b"(cast(ubyte) 255); 65 66 register!Size("size.sedan") // Register a size of a generic "sedan" into container 67 .set!"width"(200UL) 68 .set!"height"(150UL) 69 .set!"length"(500UL); 70 71 register!Size("size.smart_car") // Register a size of a generic smart car into container 72 .set!"width"(200UL) 73 .set!"height"(150UL) 74 .set!"length"(300UL); 75 76 register!Car("sedan.green") // Register a car with sedan sizes and of green color. 77 .construct("size.sedan".lref) 78 .set!"color"("color.green".lref); 79 80 register!Car("smarty.blue") // Register a car with smart car sizes and of a blue color. 81 .construct("size.smart_car".lref) 82 .set!"color"("color.blue".lref); 83 84 register!Car("sedan.blue") // Register a car with sedan car sizes and of a blue color. 85 .construct("size.sedan".lref) 86 .set!"color"("color.blue".lref); 87 } 88 ----------------- 89 90 To reference a component that has custom identity, in a configuration or reliant component, 91 use $(D_INLINECODE lref("custom-associated-identity")) notation. Seeing this type of reference, framework 92 will attempt to search component by this identity, and serve it to component that is in con- 93 struction. Thanks to unified function call syntax (UFCS) available in D programming language, 94 lref("custom-associated-identity") can be rewritten into a more pleasant view $(D_INLINECODE "custom-associated-identity".lref). 95 To extract manually a component with custom identity pass the identity to $(D_INLINECODE locate) 96 method as first argument, along with type of component. 97 98 Running fixed version of configuration, will yield in printing all three cars from code above into 99 stdout in output below. To be sure that all modifications done in this tutorial are working, run the 100 application to see following output: 101 102 ----------------- 103 You bough a new car sedan green with following specs: 104 Size: Size(200, 150, 500) 105 Color: Color(0, 255, 0) 106 You bough a new car sedan blue with following specs: 107 Size: Size(200, 150, 500) 108 Color: Color(0, 0, 255) 109 You bough a new car smarty blue with following specs: 110 Size: Size(200, 150, 300) 111 Color: Color(0, 0, 255) 112 ----------------- 113 114 Check example below. Play with it, to get the gist of named components. 115 116 License: 117 Boost Software License - Version 1.0 - August 17th, 2003 118 119 Permission is hereby granted, free of charge, to any person or organization 120 obtaining a copy of the software and accompanying documentation covered by 121 this license (the "Software") to use, reproduce, display, distribute, 122 execute, and transmit the Software, and to prepare derivative works of the 123 Software, and to permit third-parties to whom the Software is furnished to 124 do so, all subject to the following: 125 126 The copyright notices in the Software and this entire statement, including 127 the above license grant, this restriction and the following disclaimer, 128 must be included in all copies of the Software, in whole or in part, and 129 all derivative works of the Software, unless such copies or derivative 130 works are solely in the form of machine-executable object code generated by 131 a source language processor. 132 133 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 134 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 135 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 136 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 137 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 138 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 139 DEALINGS IN THE SOFTWARE. 140 141 Authors: 142 aermicioi 143 **/ 144 145 module named_dependencies; 146 147 import aermicioi.aedi; 148 import std.stdio; 149 150 /** 151 A struct that should be managed by container. 152 **/ 153 struct Color { 154 ubyte r; 155 ubyte g; 156 ubyte b; 157 } 158 159 /** 160 Size of a car. 161 **/ 162 struct Size { 163 164 ulong width; 165 ulong height; 166 ulong length; 167 } 168 169 /** 170 A class representing a car. 171 **/ 172 class Car { 173 174 private { 175 Color color_; // Car color 176 Size size_; // Car size 177 } 178 179 public { 180 181 /** 182 Constructor of car. 183 184 Constructs a car with a set of sizes. A car cannot of course have 185 undefined sizes, so we should provide it during construction. 186 187 Params: 188 size = size of a car. 189 **/ 190 this(Size size) { 191 this.size_ = size; 192 } 193 194 @property { 195 196 /** 197 Set color of car 198 199 Set color of car. A car can live with undefined color (physics allow it). 200 201 Params: 202 color = color of a car. 203 204 Returns: 205 Car 206 **/ 207 Car color(Color color) @safe nothrow { 208 this.color_ = color; 209 210 return this; 211 } 212 213 Color color() @safe nothrow { 214 return this.color_; 215 } 216 217 Size size() @safe nothrow { 218 return this.size_; 219 } 220 } 221 } 222 } 223 224 void print(Car car, string name) { 225 writeln("You bought a new car ", name," with following specs:"); 226 writeln("Size:\t", car.size()); 227 writeln("Color:\t", car.color()); 228 } 229 230 void main() { 231 SingletonContainer container = singleton(); // Creating container that will manage a color 232 scope(exit) container.terminate(); 233 234 with (container.configure) { 235 register!Color("color.green") // Register "green" color into container. 236 .set!"r"(cast(ubyte) 0) 237 .set!"g"(cast(ubyte) 255) 238 .set!"b"(cast(ubyte) 0); 239 240 register!Color("color.blue") // Register "blue" color into container. 241 .set!"r"(cast(ubyte) 0) 242 .set!"g"(cast(ubyte) 0) 243 .set!"b"(cast(ubyte) 255); 244 245 register!Size("size.sedan") // Register a size of a generic "sedan" into container 246 .set!"width"(200UL) 247 .set!"height"(150UL) 248 .set!"length"(500UL); 249 250 register!Size("size.smart_car") // Register a size of a generic smart car into container 251 .set!"width"(200UL) 252 .set!"height"(150UL) 253 .set!"length"(300UL); 254 255 register!Car("sedan.green") // Register a car with sedan sizes and of green color. 256 .construct("size.sedan".lref) 257 .set!"color"("color.green".lref); 258 259 register!Car("smarty.blue") // Register a car with smart car sizes and of a blue color. 260 .construct("size.smart_car".lref) 261 .set!"color"("color.blue".lref); 262 263 register!Car("sedan.blue") // Register a car with sedan car sizes and of a blue color. 264 .construct("size.sedan".lref) 265 .set!"color"("color.blue".lref); 266 } 267 268 269 container.instantiate(); // Boot container (or prepare managed code/data). 270 271 container.locate!Car("sedan.green").print("sedan green"); 272 container.locate!Car("sedan.blue").print("sedan blue"); 273 container.locate!Car("smarty.blue").print("smarty blue"); 274 }