Networked Games -- Design Patterns

  • Jian Huang
  • Networked Games
  • The Notes Page

    Code-Reuse is "Too Simple"

    To produce reuseable code has been a main theme throughout your past programming courses. It is considered a great thing for very obvious reasons. However, what may be of an even greater value is to reuse design. After all, without the design of how fastners are used in the entire human world, there would be "reuse" or just simply "use" of a screwdriver.

    Code reuse is a pretty good, and often sufficient, goal in an environment that does not change too much over time. In those situations, a general design might apply to many places requiring only minor variations. As soon as we expand our horizon to more dynamic needs, especially of those newly emerging applications, code reuse is suddenly a secondary issue at best. Design becomes a real first issue.

    The magic term for design reuse is "Design Pattern", which simply refers to a common and well-tested solutionf for a particular type of software problem. The term was immortalized in the popular Gang of Four book, Design Patterns: Elements of Reusable Object-Oriented Software. But really the concept of design pattern started way before, even in the "crude old" Unix world. For instance, with your in-depth knowledge of systems programming, how many places have we seen the filter pattern? Pretty much everywhere and the filter pattern made CLI very convenient and useful!

    Comparing systems programming and application development, the needs by new applications are fundamentally more diverse and volatile. It is almost safe to say that no two applications would have exactly the same requirements. Fortunately, by breaking up bigger problems into smaller ones, some common problems seem to come up over and over again as evidented by developers' online forum and newsgroups. For these diverse set of repeatable problems, design patterns provide a bonanza of help.

    Design patterns are not invented, but instead discovered and recorded. They are time-proven "best" solution to a set type of software problem. Their optimality is hard to proven, and perhaps not really needed because design is mostly still an art. Design pattern will never make the design process a mechanical and direct translation from requirements to solution, while we stand to benefit by following those well thought-out and time-tested patterns. Let us summarize:

    Writing clean elegant code is good. Code-reuse is very good. Design-reuse is very very good!


    Design Patterns

    A complete listing of all known design patterns is not necessary for this course (quite hard to find too, I bet). Fortunately, besides about two dozen design patterns, others are scarcely used in day-to-day work. Among those two dozen, the relevant ones to networked games form a even smaller set:

    We will go through the patterns in class on the whiteboard since drawing UML diagrams would be a whole lot easier and understandable that way. In the following, let's cover a few of the design principles that the community were able to summarize from all the patterns they have found over the years.

    Design principles:

    Let's first talk about the strategy pattern, also known as the facade pattern in some circles. It defines a family of algorithms encapsulates each one, and makes them interchangeable. This pattern lets the algorithm vary independently from clients that use it. Try this pattern on the following problem. You design a game where characters (king, queen, knight, troll, ...) fight with a weapon. How extensible can your design be?

    The observer pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically. Note the design's Subject and Observer interfaces.

    The factory pattern defines an interface for creating an object, but lets subclasses descide which class to instantiate. Factory method lets a class defer instantiation to subclasses.

    The singleton pattern ensures a class has only one instance, and provides a global point of access to it.

    The iterator pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representations.

    The visitor pattern is used to add capabilities to a composite of objects and encapsulation is not important.