Design Pattern Examples
Overview of object-oriented design patterns
Flyweight_Exercise.cs
Go to the documentation of this file.
1
5
6using System;
7using System.Collections.Generic;
8using System.Text;
9
11{
31 internal class Flyweight_Exercise
32 {
48 int _Flyweight_GenerateBigResource(int numImages, int width, int height)
49 {
50 if (numImages < 1)
51 {
52 numImages = 1;
53 }
54 else if (numImages > 9)
55 {
56 numImages = 9;
57 }
58 if (width < 3)
59 {
60 width = 3;
61 }
62 if (height < 3)
63 {
64 height = 3;
65 }
66
67 List<string> image = new List<string>();
68 for (int row = 0; row < height; ++row)
69 {
70 string image_row = "";
71 for (int imageIndex = 0; imageIndex < numImages; imageIndex++)
72 {
73 if (row == 0 || (row + 1) == height)
74 {
75 // top and bottom row are the same.
76 image_row += "+" + new string('-', width - 2) + "+";
77 }
78 else
79 {
80 // All other rows are each the same -- except that
81 // each image is "numbered" where the background of the
82 // image reflects the number of the image (0, 1, 2, etc.).
83 char c = imageIndex.ToString()[0];
84 image_row += '|' + new string(c, width - 2) + '|';
85 }
86 }
87 image.Add(image_row);
88 }
89
90 int resourceId = BigResourceManager.AddResource(image);
91 return resourceId;
92 }
93
94
101 List<char[]> _Flyweight_GenerateDisplay(int width, int height)
102 {
103 List<char[]> display = new List<char[]>();
104
105 for (int row = 0; row < height; ++row)
106 {
107 display.Add(new char[width]);
108 }
109
111 return display;
112 }
113
114
119 void _Flyweight_ShowDisplay(List<char[]> display)
120 {
121 StringBuilder output = new StringBuilder();
122 foreach (char[] row in display)
123 {
124 output.Append(" ");
125 foreach (char col in row)
126 {
127 output.Append(col);
128 }
129 output.Append(Environment.NewLine);
130 }
131 Console.WriteLine(output);
132 }
133
134
139 void _Flyweight_ClearDisplay(List<char[]> display)
140 {
141 foreach (char[] row in display)
142 {
143 for (int index = 0; index < row.Length; ++index)
144 {
145 row[index] = '~';
146 }
147 }
148 }
149
150
160 void _Flyweight_MoveFlyweights(List<Flyweight_Class> flyweightInstances, int display_width, int display_height)
161 {
162 foreach (Flyweight_Class flyweight in flyweightInstances)
163 {
164 Flyweight_Context context = flyweight.Context;
165 int image_width = flyweight.ImageWidth;
166 int image_height = flyweight.ImageHeight;
167 double newx = context.Position_X + context.Velocity_X;
168 double newy = context.Position_Y + context.Velocity_Y;
169
170 if (newx < 0 || (newx + image_width) > display_width)
171 {
172 // Bounce off left or right edge.
173 context.Velocity_X = -context.Velocity_X;
174 if (newx < 0)
175 {
176 newx = 0;
177 }
178 else
179 {
180 newx = display_width - image_width;
181 }
182 }
183
184 if (newy < 0 || (newy + image_height) > display_height)
185 {
186 // Bounce off top or bottom edge.
187 context.Velocity_Y = -context.Velocity_Y;
188 if (newy < 0)
189 {
190 newy = 0;
191 }
192 else
193 {
194 newy = display_height - image_height;
195 }
196 }
197
198 context.Position_X = newx;
199 context.Position_Y = newy;
200 flyweight.Context = context;
201 }
202 }
203
204
210 void _Flyweight_RenderFlyweights(List<Flyweight_Class> flyweightInstances, List<char[]> displayArea)
211 {
212 // Render the image into the "display", one image for each instance
213 // of the Flyweight class.
214 foreach (Flyweight_Class flyweight in flyweightInstances)
215 {
216 flyweight.Render(displayArea,
217 flyweight.Context.OffsetXToImage,
218 flyweight.ImageWidth,
219 flyweight.ImageHeight,
220 (int)flyweight.Context.Position_X,
221 (int)flyweight.Context.Position_Y);
222 }
223 }
224
231 double GenerateVelocity(Random randomizer)
232 {
233 double speed = (randomizer.Next(1, 5) / 5.0);
234 double direction = ((randomizer.Next(100) > 50) ? 1.0 : -1.0);
235 return speed * direction;
236 }
237
253 List<Flyweight_Class> _Flyweight_GenerateFlyweightClasses(int bigResourceId, int numFlyweights,
254 int image_width, int image_height, int display_width, int display_height)
255 {
256 List<Flyweight_Class> flyweightInstances = new List<Flyweight_Class>();
257
258 Random randomizer = new Random();
259 // Generate the instances of the flyweight class, randomizing the position
260 // of each flyweight within the display.
261 for (int index = 0; index < numFlyweights; ++index)
262 {
263 Flyweight_Context context = new Flyweight_Context();
264 context.OffsetXToImage = index * image_width;
265 context.ImageWidth = image_width;
266 context.ImageHeight = image_height;
267 // Make sure the entire image can be rendered at each position
268 context.Position_X = randomizer.Next(0, display_width - image_width);
269 context.Position_Y = randomizer.Next(0, display_height - image_height);
270 // Randomize the initial velocity.
271 context.Velocity_X = GenerateVelocity(randomizer);
272 context.Velocity_Y = GenerateVelocity(randomizer);
273
274 // Create an instance of the Flyweight_Class for the given big
275 // resource and with the new context.
276 Flyweight_Class? flyweightInstance = BigResourceManager.CreateFlyweight(bigResourceId, context);
277 if (flyweightInstance != null)
278 {
279 flyweightInstances.Add(flyweightInstance);
280 }
281 else
282 {
283 Console.WriteLine(" Error! Failed to find big resource ID {}, which is needed for the flyweight.", bigResourceId);
284 }
285 }
286 return flyweightInstances;
287 }
288
292 // ! [Using Flyweight in C#]
293 public void Run()
294 {
295 Console.WriteLine();
296 Console.WriteLine("Flyweight Exercise");
297
298 // Define the display and image size.
299 const int DISPLAY_WIDTH = 80;
300 const int DISPLAY_HEIGHT = 20;
301 const int IMAGE_WIDTH = 30;
302 const int IMAGE_HEIGHT = 5;
303 const int NUMFLYWEIGHTS = 5;
304 const int NUM_ITERATIONS = 1000;
305
306 int bigResourceId = _Flyweight_GenerateBigResource(NUMFLYWEIGHTS, IMAGE_WIDTH, IMAGE_HEIGHT);
307 List<Flyweight_Class> flyweightInstances;
308 flyweightInstances = _Flyweight_GenerateFlyweightClasses(bigResourceId, NUMFLYWEIGHTS,
309 IMAGE_WIDTH, IMAGE_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
310
311 // Create the "display".
312 // We use a list of character arrays so we can write to each
313 // character position individually. In C#, strings are immutable
314 // and changing a character in a string is not allowed.
315 List<char[]> displayArea = _Flyweight_GenerateDisplay(DISPLAY_WIDTH, DISPLAY_HEIGHT);
316
317 // Finally, display the rendered output.
318 Console.WriteLine(" The image rendered {0} times:", NUMFLYWEIGHTS);
319 Console.WriteLine(""); // Blank line for iteration count
320 _Flyweight_RenderFlyweights(flyweightInstances, displayArea);
321 _Flyweight_ShowDisplay(displayArea);
322
323 // Now let's have some fun and bounce those images around for a while!
324 // (Or until a keypress.)
325 int cursorLeft = Console.CursorLeft;
326 int cursorTop = Console.CursorTop;
327 cursorTop -= DISPLAY_HEIGHT + 1;
328 for (int index = 0; index < NUM_ITERATIONS; ++index)
329 {
330 Console.SetCursorPosition(cursorLeft, cursorTop - 1);
331 Console.WriteLine(" {0,5}/{1} iterations [press a key to exit early]", index + 1, NUM_ITERATIONS);
332 Console.SetCursorPosition(cursorLeft, cursorTop);
333
334 _Flyweight_ClearDisplay(displayArea);
335 _Flyweight_MoveFlyweights(flyweightInstances, DISPLAY_WIDTH, DISPLAY_HEIGHT);
336 _Flyweight_RenderFlyweights(flyweightInstances, displayArea);
337 _Flyweight_ShowDisplay(displayArea);
338 System.Threading.Thread.Sleep(16); // 60 frames a second
339 if (Console.KeyAvailable)
340 {
341 Console.ReadKey();
342 break;
343 }
344 }
345 Console.WriteLine(" Done.");
346 }
347 // ! [Using Flyweight in C#]
348 }
349}
static double GenerateVelocity(void)
Generate a random velocity, which includes a speed and a direction. The velocity is 0....
Represents a manager for big resources. Also provides the class factory for the Flyweight_Class insta...
static int AddResource(List< string > rawResource)
Add a new big resource and return the ID of the resource.
static ? Flyweight_Class CreateFlyweight(int bigResourceId, Flyweight_Context context)
Create a new instance of the Flyweight_Class associated with the given big resource and a context,...
Associates a context with a big resource.
int ImageHeight
Retrieve the "image" height from underlying big resource.
int ImageWidth
Retrieve the "image" width from underlying big resource.
void Render(List< char[]> display, int offset_x, int image_width, int image_height, int position_x, int position_y)
Render the image associated with this flyweight instance into the given display at the given position...
Flyweight_Context Context
Retrieve or set the context for this class instance.
Example of using the Flyweight Pattern in C#.
void _Flyweight_RenderFlyweights(List< Flyweight_Class > flyweightInstances, List< char[]> displayArea)
Render the image into the display, once for each flyweight instance.
int _Flyweight_GenerateBigResource(int numImages, int width, int height)
Generate a big resource, in this case, a text master "image" of the specified height,...
double GenerateVelocity(Random randomizer)
Generate a random velocity, which includes a speed and a direction. The velocity is 0....
void _Flyweight_MoveFlyweights(List< Flyweight_Class > flyweightInstances, int display_width, int display_height)
Move the given flyweight instances within the display, bouncing them off the edges of the display.
List< char[]> _Flyweight_GenerateDisplay(int width, int height)
Generate a display area in which to render the big resource.
List< Flyweight_Class > _Flyweight_GenerateFlyweightClasses(int bigResourceId, int numFlyweights, int image_width, int image_height, int display_width, int display_height)
Helper method to generate the specified number of flyweight class instances and associate those insta...
void Run()
Executes the example for the Flyweight Pattern in C#.
void _Flyweight_ClearDisplay(List< char[]> display)
Clear the "display" to a background image, erasing whatever was there before.
void _Flyweight_ShowDisplay(List< char[]> display)
Render the display to the screen.
The namespace containing all Design Pattern Examples implemented in C#.
Represents the context for an instance of the Flyweight_Class. In this case, the context includes pos...