@@ -19,25 +19,25 @@ attack string. When the monster attacks our hero, that text will be shown to the
1919user somehow. (We don't care how here.)
2020
2121The designers tell us that monsters come in a variety of different * breeds* ,
22- like "dragon" or "troll." Each breed describes a * kind* of monster that exists
22+ like "dragon" or "troll". Each breed describes a * kind* of monster that exists
2323in the game, and there can be multiple monsters of the same breed running around
2424in the dungeon at the same time.
2525
26- The breed determines a monster's starting health: dragons start off with more
27- than trolls, making them harder to kill. It also determines the attack string:
26+ The breed determines a monster's starting health -- dragons start off with more
27+ than trolls, making them harder to kill. It also determines the attack string --
2828all monsters of the same breed attack the same way.
2929
3030### The typical OOP answer
3131
32- Given that game design, we fire up our text editor and start coding. According
32+ With that game design in mind , we fire up our text editor and start coding. According
3333to the design, a dragon <span name =" isa " >is a</span > kind of monster, a troll is
3434another kind, and so on with the other breeds. Thinking object-oriented, that
3535leads us to a ` Monster ` base class:
3636
3737<aside name =" isa " >
3838
3939This is the so-called "is-a" relationship. In conventional OOP thinking, since a
40- dragon "is-a" monster, we model that by making Dragon a subclass of Monster. As
40+ dragon "is-a" monster, we model that by making ` Dragon ` a subclass of ` Monster ` . As
4141we'll see, subclassing is only one way of enshrining a conceptual relation like
4242that into code.
4343
@@ -66,17 +66,17 @@ Exclamation points make everything more exciting!
6666
6767</aside >
6868
69- Each class derived from ` Monster ` passes in the starting health, and overrides
69+ Each class derived from ` Monster ` passes in the starting health and overrides
7070` getAttack() ` to return the attack string for that breed. Everything works as
71- expected, and before long we've got our hero running around slaying a variety of
71+ expected, and before long, we've got our hero running around slaying a variety of
7272beasties. We keep slinging code, and before we know it, we've got dozens of
7373monster subclasses, from acidic slimes to zombie goats.
7474
7575Then, strangely, things start to bog down. Our designers ultimately want to have
7676* hundreds* of breeds, and we find ourselves spending all of our time writing
77- these little seven line subclasses and recompiling. It gets worse: the designers
77+ these little seven- line subclasses and recompiling. It gets worse -- the designers
7878want to start tuning the breeds we've already coded. Our formerly productive
79- work day degenerates to:
79+ workday degenerates to:
8080
81811 . Get email from designer asking to change health of troll from
8282 48 to 52.
@@ -92,7 +92,7 @@ work day degenerates to:
92926 . Repeat.
9393
9494We spend the day frustrated because we've turned into data monkeys. Our
95- designers are frustrated because it takes them forever just to get a simple
95+ designers are frustrated because it takes them forever to get a simple
9696number tuned. What we need is the ability to change breed stats without having
9797to recompile the whole game every time. Even better, we'd like designers to be
9898able to create and tune breeds without * any* programmer intervention at all.
@@ -103,12 +103,12 @@ At a very high level, the problem we're trying to solve is pretty simple. We
103103have a bunch of different monsters in the game, and we want to share certain
104104attributes between them. A horde of monsters are beating on the hero, and we
105105want some of them to use the same text for their attack. We define that by
106- saying that all of those monsters are the same "breed," and that the breed
106+ saying that all of those monsters are the same "breed", and that the breed
107107determines the attack string.
108108
109- We decided to implement this concept using inheritance, since it lines up with
110- our intuition of classes: A dragon is a monster, and each dragon in the game is
111- an instance of this dragon "class." Defining each breed as a subclass of an
109+ We decided to implement this concept using inheritance since it lines up with
110+ our intuition of classes. A dragon is a monster, and each dragon in the game is
111+ an instance of this dragon "class". Defining each breed as a subclass of an
112112abstract base ` Monster ` class, and having each monster in the game be an
113113instance of that derived breed class mirrors that. We end up with a class
114114hierarchy like this:
@@ -152,16 +152,16 @@ same breed: starting health and the attack string.
152152To associate monsters with breeds, we give each ` Monster ` instance a reference
153153to a ` Breed ` object containing the information for that breed. To get the attack
154154string, a monster just calls a method on its breed. The ` Breed ` class
155- essentially defines a monster's "type." Each breed instance is an * object* that
155+ essentially defines a monster's "type". Each breed instance is an * object* that
156156represents a different conceptual * type* , hence the name of the pattern: Type
157157Object.
158158
159159What's especially powerful about this pattern is that now we can define new
160- * types* of things without complicating the codebase at all: we 've essentially
160+ * types* of things without complicating the codebase at all. We 've essentially
161161lifted a portion of the type system out of the hard-coded class hierarchy into
162162data we can define at runtime.
163163
164- We can create hundreds of different breeds just by instantiating more instances
164+ We can create hundreds of different breeds by instantiating more instances
165165of ` Breed ` with different values. If we create breeds by initializing them from
166166data read from some configuration file, we have the ability to define new types
167167of monsters completely in data. So easy, a designer could do it!
@@ -170,7 +170,7 @@ of monsters completely in data. So easy, a designer could do it!
170170
171171Define a ** type object** class and a ** typed object** class. Each type object
172172instance represents a different logical type. Each typed object stores a
173- ** reference to the type object that describes its type. **
173+ ** reference to the type object that describes its type** .
174174
175175Instance-specific data is stored in the typed object instance, and data or
176176behavior that should be shared across all instances of the same conceptual type
@@ -183,11 +183,11 @@ having a fixed set of hard-coded subclasses.
183183
184184This pattern is useful anytime you need to define a variety of different "kinds"
185185of things, but baking the kinds into your language's type system is too rigid.
186- In particular, it's useful when either of these are true:
186+ In particular, it's useful when either of these is true:
187187
188188 * You don't know what types you will need up front. (For example, what if our
189189 game needed to support downloading content that contained new breeds of
190- monster ?)
190+ monsters ?)
191191
192192 * You want to be able to modify or add new types without having to recompile
193193 or change code.
@@ -207,18 +207,18 @@ automatically. The data that defines each class is automatically compiled into
207207the static memory segment of the executable and just works.
208208
209209With the Type Object pattern, we are now responsible for managing not only our
210- monsters in memory, but also their * types* : we have to make sure all of the
210+ monsters in memory, but also their * types* -- we have to make sure all of the
211211breed objects are instantiated and kept in memory as long as our monsters need
212212them. Whenever we create a new monster, it's up to us to ensure that it's
213213correctly initialized with a reference to a valid breed.
214214
215215We've freed ourselves from some of the limitations of the compiler, but the cost
216- is we have to re-implement some of what it used to be doing for us.
216+ is that we have to re-implement some of what it used to be doing for us.
217217
218218<aside name =" vtable " >
219219
220220Under the hood, C++ virtual methods are implemented using something called a
221- "virtual function table", or just "vtable." A vtable is a simple struct
221+ "virtual function table", or just "vtable". A vtable is a simple ` struct `
222222containing a set of function pointers, one for each virtual method in a class.
223223There is one vtable in memory for each class. Each instance of a class has a
224224pointer to the vtable for its class.
@@ -235,7 +235,7 @@ pattern applied to C, handled automatically by the compiler.
235235
236236### It's harder to define * behavior* for each type
237237
238- With subclassing, you can override a method and do whatever you want to:
238+ With subclassing, you can override a method and do whatever you want to --
239239calculate values procedurally, call other code, etc. The sky is the limit. We
240240could define a monster subclass whose attack string changed based on the phase
241241of the moon if we wanted to. (Handy for werewolves, I suppose.)
@@ -251,12 +251,12 @@ monster needed to use different AI algorithms, using this pattern becomes more
251251challenging.
252252
253253There are a couple of ways we can get around this limitation. A simple solution
254- is to have a fixed set of pre-defined behaviors, and then use data in the type
254+ is to have a fixed set of pre-defined behaviors and then use data in the type
255255object to simply * select* one of them. For example, let's say our monster AI
256256will always be either "stand still", "chase hero", or "whimper and cower in
257257fear" (hey, they can't all be mighty dragons). We can define <span
258- name="fn">functions</span > to implement each of those behaviors. Then we can
259- associate an AI algorithm with a breed by simply having it store a pointer to
258+ name="fn">functions</span > to implement each of those behaviors. Then, we can
259+ associate an AI algorithm with a breed by having it store a pointer to
260260the appropriate function.
261261
262262<aside name =" fn " >
@@ -268,7 +268,7 @@ type objects.
268268
269269Another more powerful solution is to actually support defining behavior
270270completely in <span name =" data " >data</span >. The <a class="gof-pattern"
271- href="http://c2.com/cgi-bin/wiki?InterpreterPattern">Interpreter </a >, and <a
271+ href="http://c2.com/cgi-bin/wiki?InterpreterPattern">Interpreter </a > and <a
272272class="pattern" href="bytecode.html">Bytecode</a > patterns both let us build
273273objects that represent behavior. If we read in a data file and use that to
274274create a data structure for one of these patterns, we've moved the behavior's
@@ -314,7 +314,7 @@ here on out is bonus.
314314
315315With what we have now, we construct a monster directly and are responsible for
316316passing in its breed. This is a bit backwards from how regular objects are
317- instantiated in most OOP languages: we don't usually allocate a blank chunk of
317+ instantiated in most OOP languages -- we don't usually allocate a blank chunk of
318318memory and then * give* it its class. Instead, we call a constructor function on
319319the class itself, and it's responsible for giving us a new instance.
320320
@@ -347,7 +347,7 @@ implementation, creating a monster looked like:
347347There's another minor difference here. Because the sample code is in C++, we can
348348use a handy little feature: * friend classes.*
349349
350- We've made ` Monster ` &rsquo ; s constructor private which prevents anyone from
350+ We've made ` Monster ` &rsquo ; s constructor private, which prevents anyone from
351351calling it directly. Friend classes sidestep that restriction so ` Breed ` can
352352still access it. This means the * only* way to create monsters is by going
353353through ` newMonster() ` .
@@ -394,7 +394,7 @@ Just like we did with our original OOP solution, we can solve this using
394394inheritance. Only, this time, instead of using our language's inheritance
395395mechanism, we'll implement it ourselves within our type objects.
396396
397- To keep things simple, we'll just support single inheritance. In the same way
397+ To keep things simple, we'll only support single inheritance. In the same way
398398that a class can have a parent base class, we'll allow a breed to have a parent
399399breed:
400400
@@ -404,13 +404,13 @@ When we construct a breed, we give it a parent that it inherits from. We can
404404pass in ` NULL ` for a base breed that has no ancestors.
405405
406406To make this useful, a child breed needs to control which attributes are
407- inherited from its parent and which it overrides and specifies itself. For our
407+ inherited from its parent and which attributes it overrides and specifies itself. For our
408408example system, we'll say that a breed overrides the monster's health by having
409- a non-zero value, and overrides the attack by having a non-` NULL ` string.
409+ a non-zero value and overrides the attack by having a non-` NULL ` string.
410410Otherwise, the attribute will be inherited from its parent.
411411
412412There are two ways we can implement this. One is to handle the delegation
413- dynamically, every time the attribute is requested, like this:
413+ dynamically every time the attribute is requested, like this:
414414
415415^code 10
416416
@@ -465,9 +465,9 @@ fields, the `Troll Archer` and `Troll Wizard` breeds inherit from the base
465465Since both of them have zero for their health, they'll inherit it from the base
466466` Troll ` breed instead. This means now our designer can tune the health in
467467` Troll ` and all three breeds will be updated. As the number of breeds and the
468- number of different attributes each breed has increases , this can be a big
468+ number of different attributes each breed has increase , this can be a big
469469time-saver. Now, with a pretty small chunk of code, we have an open-ended system
470- that puts control in our designer's hands and makes the best use of their time.
470+ that puts control in our designers' hands and makes the best use of their time.
471471Meanwhile, we can get back to coding other features.
472472
473473## Design Decisions
@@ -483,14 +483,14 @@ able to easily understand it. The simpler we can make it, the more usable it
483483will be. So what we'll cover here is the well-trodden design space, and we'll
484484leave the far reaches for the academics and explorers.
485485
486- ### Is the Type Object encapsulated or exposed?
486+ ### Is the type object encapsulated or exposed?
487487
488488In our sample implementation, ` Monster ` has a reference to a breed, but it
489489doesn't publicly expose it. Outside code can't get directly at the monster's
490490breed. From the codebase's perspective, monsters are essentially typeless, and
491491the fact that they have breeds is an implementation detail.
492492
493- We can easily change this and allow Monster to return its Breed:
493+ We can easily change this and allow ` Monster ` to return its ` Breed ` :
494494
495495<span name =" null " ></span >
496496
@@ -505,7 +505,7 @@ never be returned.
505505</aside >
506506
507507Doing this changes the design of ` Monster ` . The fact that all monsters have
508- breeds is now a publicly- visible part of its API. There are benefits with either
508+ breeds is now a publicly visible part of its API. There are benefits with either
509509choice.
510510
511511 * ** If the type object is encapsulated:**
@@ -540,7 +540,7 @@ choice.
540540 get to breeds directly, they wouldn't be able to call it.
541541
542542 * * The type object is now part of the object's public API.* In general,
543- narrow interfaces are easier to maintain than wide ones: the less you
543+ narrow interfaces are easier to maintain than wide ones -- the less you
544544 expose to the rest of the codebase, the less complexity and maintenance
545545 you have to deal with. By exposing the type object, we widen the
546546 object's API to include everything the type object provides.
@@ -596,7 +596,7 @@ zombie one.
596596 * * There's less object creation.* In our example, if the type can't
597597 change, we'll be forced to burn CPU cycles creating a new zombie
598598 monster, copying over any attributes from the original monster that need
599- to be preserved, and then deleting it. If we can simply change the type,
599+ to be preserved, and then deleting it. If we can change the type,
600600 all that work gets replaced by a simple assignment.
601601
602602 * * We need to be careful that assumptions are met.* There's a fairly tight
@@ -617,7 +617,7 @@ zombie one.
617617 that needs sharing between your type objects, why make things hard on
618618 yourself?
619619
620- * * Can lead to duplicated effort.* I've yet to see an authoring system
620+ * * It can lead to duplicated effort.* I've yet to see an authoring system
621621 where designers * didn't* want some kind of inheritance. When you've got
622622 fifty different kinds of elves, having to tune their health by changing
623623 the same number in fifty different places * sucks* .
@@ -633,8 +633,8 @@ zombie one.
633633
634634 * * Looking up attributes is slower.* To get a given piece of data from a
635635 type object, we may now need to walk up the inheritance chain to find
636- the type that ultimately decides the value. If we're in performance
637- critical code, we may not want to spend time on this.
636+ the type that ultimately decides the value. If we're in
637+ performance- critical code, we may not want to spend time on this.
638638
639639 * ** Multiple inheritance:**
640640
0 commit comments