Chapter 1. Hello, Design Patterns!

Almost every computer programming book starts with a "Hello, World!" chapter to introduce the topic. Since this book is all about design patterns, let's start with "Hello, Design Patterns!"

As you've already picked up this book, you are probably familiar with the notion of design patterns in object-oriented programming. A design pattern is useful as an abstraction tool for solving design problems in other fields like engineering and architecture. The notion was borrowed by software development for a similar purpose. A design pattern is a template for an object or class design that solves a recurring problem in a particular domain.

This chapter provides a brief history of design patterns and their relationships with the Cocoa Touch technologies. It discusses issues that can affect a design, talks about object notation used in the book, and explains how design patterns are organized.

What This Book Is

This book is for any professional or aspiring iOS developer who wants to take advantage of design patterns to make his or her software development efforts more productive and more fun! The purpose of this book is to show you how to put design patterns into action in iOS application development. I will focus on applicability of various design patterns with the Cocoa Touch framework and its related technologies.

Although some of the principles and notions may also be applicable to Cocoa Touch's big brother, Cocoa for Mac OS X, there is no guarantee that they will work perfectly with the full-blown Cocoa. You can use this book as a quick reference to design patterns in Objective-C.

What you'll learn:

  • The basic concepts of various design patterns.

  • How to apply them to your code based on different design scenarios.

  • How design patterns can strengthen your apps.

The website for this book is www.objective-c-design-patterns.com or www.objectivecdesignpatterns.com. Feel free to share your success stories and hurdles on using design patterns in your projects.

The source code is available at www.apress.com

What You Need Before You Can Begin

Just like any other iOS application development book, you'll need a copy of Xcode and iOS SDK to run the sample code in this book. The sample projects for this book were compiled and tested using Xcode version 3.2.5 and iOS SDK 4.2, so any newer versions should also work well. There are many free/paid tools available for developing iOS applications on platforms other than Mac OS X, but there's no guarantee that any of the samples from this book will work as they should if they are created on those other platforms.

This book also covers some aspects of designing an iOS application. You may want to download/purchase some software tools to help build wireframes and UI layouts for practicing or designing real applications. The wireframes in this book were created using OmniGraffle (www.omnigroup.com/products/omnigraffle/). The website also provides an area where you can download various free stencils or wireframe templates.

Class and object diagrams were used extensively in this book, but the choices of software tools for modeling class and objects are very limited. As of this writing, most of them are based on some standard notations that are only applicable to other object-oriented programming languages such as C++, Java, and C#. Objective-C has some special language features that are hard to represent with standard notations, such as categories and extensions (anonymous categories). For this reason, I have invented some notations just for the special features; they are explained in the "Objects and Classes Used In This Book" section later in this chapter. You can use a graphic authoring tool of your choice to draw Objective-C classes and objects based on the invented notations. Hopefully, there will be a set of standardized object modeling notations for Objective-C coming out soon.

What You Need to Know Before You Can Begin

This book is in a pro series, so it's not "iOS development 101" or "Start using Objective-C in 24 hours." I assume that you, the reader, have basic knowledge of the iOS SDK (the Cocoa Touch framework). Further, you should feel comfortable with the Objective-C programming language. Otherwise, you will miss many of the insights and advanced techniques and tricks presented in this book.

Although this book is targeted at intermediate and advanced developers, you don't need to have in-depth knowledge of design patterns in order to pick up their concepts. If you were exposed to some design patterns somewhere in your career path, you will still benefit from the explanations in this book. Every pattern chapter uses some everyday analogies to assimilate the theme of the design pattern. Also, there are tips and notes to dispel any confusion where applicable.

Are you ready? Let's roll!

Design Déjà-vu

As a developer, you have likely had the feeling that "I've solved this problem before but don't know exactly where or how." This happens all the time, especially when you're working on particular types of projects repeatedly. For example, every database application has features like database access so that your application can store and retrieve its data. If you do a good job recording the details of the problems and how you solved them, you can easily reapply the strategies instead of reinventing them.

The experiences of some of the most common design déjà-vu scenarios as well as strategies applicable to them were first authoritatively described and cataloged in Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley Professional, 1994). It captured design experiences in designing object-oriented software in a form that people could use effectively as design patterns. Ironically, the predecessor of Cocoa (Touch) frameworks, NEXTSTEP, was designed with many elegant, reusable object-oriented software design patterns and it played a major role as a source of inspiration for the original "Gang of Four" (a popular nickname for the authors of the above book).

According to Design Patterns: Elements of Reusable Object-Oriented Software,

A design pattern is a description of communicating objects and classes that are customized to solve a general design problem in a particular context.

In short, a design pattern is a customized solution to a problem in a context. The context is a recurring situation in which the problem occurs. The problem is the goal you are trying to achieve in this context. The same problem in a different context may have different constraints and challenges. And the customized solution is a design that achieves the goal in a particular context and resolves the constraints that come with it.

A design pattern abstracts the key aspects of a particular object-oriented design problem or issue that has proven to be effective over time. It expresses important insights on object-oriented designs. Some principles of design influence design patterns. These principles are rules of thumb for constructing reusable and maintainable object-oriented applications, such as "favor object composition over class inheritance" and "program to an interface, not an implementation."

For example, if you encapsulate and isolate some parts of a program that vary by defining interfaces for them, they can vary independently of other parts of the program because they are not tied to any specifics. You can then change or extend those variable parts without affecting the other parts of the program. The program consequently becomes more flexible and robust to change because you eliminate dependencies and reduce couplings between parts. These benefits make design patterns important when you want to write reusable software.

Programs (and the objects and classes within) that adapt and use design patterns in their design will be more reusable, more extensible, and easier to change in the future. Moreover, programs that are based on design patterns tend to be more elegant and efficient than other programs that aren't, as they require fewer lines of code to accomplish the same goal.

The Origin of Design Patterns - Model, View, and Controller (MVC)

The Model-View-Controller design pattern (MVC) and its variants have been around at least since the early days of Smalltalk. The design pattern is fundamental to many mechanisms and technologies in Cocoa Touch.

Objects in a MVC design patterns are segregated into one of three roles in an application: model, view, or controller. The MVC pattern also defines the way objects communicate with each other across abstract boundaries of their roles. MVC contributes important factors to a good Cocoa Touch application design. A major step in designing an application is to choose one of these three groups an object or a class should fall into. It should be relatively painless to use any technologies packaged from the Cocoa Touch framework if the application has a well-defined MVC segregation.

The pattern itself is not an absolute pattern of its own; rather, it is compound pattern in that it comprises several other elemental patterns. Those elemental patterns are discussed in detail throughout the pattern catalog of this book.

Many objects in MVC applications are more easily extensible and reusable than other applications that are not based on MVC, as their interfaces tend to be better defined. What's more, many Cocoa Touch technologies and architectures are built upon the MVC pattern and require your applications and objects play by the rules set for the MVC roles.

The following sections describe how each of the MVC roles plays a part in the architecture.

Encapsulating Data and Basic Behaviors In Model Objects

Model objects maintain an application's data as well as define the special logic that manipulates it. They are reusable because they represent knowledge that is applicable to a specific problem domain. For example, a model object might represent a complex data structure for what the user has drawn on the screen—or be as simple as an item in a to-do list application.

Once any data that contains persistent information of the application is loaded, it should be put in the model objects. In an ideal situation, a model object should not have any explicit association with any user interface used for presenting and editing it.

Presenting Information to the User with View Objects

A view object can respond to user actions and knows how to present itself onscreen. A view object usually presents data obtained from model objects from the application. It can work with a portion of a model object, a complete model object, or even multiple different model objects. Often, in conjunction with user actions, it allows modifications to that data.

Despite the close relationship between a view object and a model object, view objects are not coupled with model objects in an MVC application. Except for performance reasons (such as when a view needs to cache data), the view should not be used for storing the data it is presenting.

Since view objects can work with many different model objects, they tend to be reusable and consistent across different applications. The UIKit framework offers a variety of collections of view classes that you can reuse in your own applications.

Tying up the Model to the View with Controller Objects

A controller object acts like a middleman between view and model objects. As a middleman or mediator, it can establish a communication channel through which its views can acknowledge and respond to changes in the models.

Besides the mediating role, controller objects can perform other operations for an application, such as managing the life cycles of other objects, performing setup, and coordinating tasks for the application.

For instance, a value that's a result of a user action through a view object, such as entering a value in a text input box, can be passed to a controller object. The controller object may also tell the view object to change its appearance or behavior based on the same user action, such as disabling a text input box.

Depending on the required design, controller objects can be either reusable or non-reusable (concrete).

MVC as a Compound Design Pattern

MVC is not a bottom-line design pattern by itself. It contains several more relatively primitive design patterns, which are discussed in the pattern catalog throughout this book. The elemental design patterns in MVC work together to define functional collaborations that are characteristic of an MVC application.

The Cocoa (Touch) version of MVC comprises the Composite, Command, Mediator, Strategy, and Observer patterns.

  • Composite (Chapter 13): The view objects forms a view hierarchy in a coordinated manner. The view components in the hierarchy can range from compound views (such as table views) to individual views (such as text boxes or buttons). Each of the view nodes at any level can respond to user actions and draw itself onscreen.

  • Command (Chapter 20): This is a target-action mechanism in which view objects can defer an execution on other objects, such as controllers, until certain events have occurred. The mechanism incorporates the Command pattern.

  • Mediator (Chapter 11): A controller object plays a middleman role that adopts the Mediator pattern; it forms a bi-directional conduit for the flow of data between model and view objects. Changes in model are communicated to view objects through the controller objects of an application.

  • Strategy (Chapter 19): A controller can be a "strategy" for any view object. A view object isolates itself in order to maintain its sole duty as a data presenter and delegates all application-specific decisions of the interface behavior to its "strategy" object (the controller).

  • Observer (Chapter 12): A model object keeps interested objects such as controllers updated with any changes to its internal state.

Figure 1-1 shows how these patterns work together in a fictitious scenario.

An illustrative example on how Model, View, and Controller interact as a group of different entities

Figure 1-1. An illustrative example on how Model, View, and Controller interact as a group of different entities

This is what's happening in Figure 1-1:

  1. The user creates a touch event by touching or dragging her finger across the canvas view. The actual view (layer) being touched is right at a particular level in a view composite. The canvas (view) forwards the touch information to its view controller.

  2. The controller object receives the touch event and its related information. It then applies a strategy to change the state of a model and/or request the view object to update its behavior or appearance based on the same event.

  3. Once a change has occurred and has been updated in the model object, the model object notifies all registered observer objects such as controllers.

  4. The controller acts as a mediator to communicate any changed data from the model to the view(s), so they can update their appearances accordingly.

Issues That Can Affect Your Design

Design patterns can certainly improve your system designs in many ways. But there are a few design principles that can also affect your designs. Some of them are for software designs in general but some are specific to Objective-C and Cocoa Touch. I will discuss each of them in the following sections.

Programming To An Interface, Not An Implementation

Many software developers understand object-oriented concepts like classes, objects, inheritance, polymorphism, and interfaces. But what's the difference between class inheritance and interface inheritance (subtyping)? An interface defines a type, and interface inheritance (subtyping) allows you to use an object in place of another. On the other hand, class inheritance is a mechanism for defining an object's implementation and type by reusing functionality in parent class or just simply sharing code and representation. Class inheritance allows you to define a new kind of class rapidly by inheriting most of what you need from existing classes for free. In fact, there is a close relationship between class and type. The contrast, though, is that an object can have many types while objects of different classes have the same type.

Defining families of classes with identical interfaces is important because polymorphism depends on the interfaces! Other object-oriented programming languages like Java allow developers to define a type of "interface" (compared to a class) that defines a "contract" between clients and concrete objects being used. Objective-C has a similar kind of thing called protocol. A protocol also acts like a contract of objects but can't be instantiated as an object itself. Implementing a protocol or inheriting from an abstract class let objects share the same interfaces (I'll discuss some issues relating to using protocol versus abstract base class in the next section). So all objects of the subtypes can respond to the requests in the interface of the protocol or abstract class.

There are two benefits from the practice:

  • As long as the objects conform to the interface that clients expect, the clients shouldn't be aware of the exact types of objects they use.

  • Clients only know about the protocol(s) or abstract class(es) defining the interface, so the clients don't know anything about the objects' classes.

This leads to the principle of reusable object-oriented software design according to the Gang of Four book:

Program to an interface, not an implementation.

A common practice in client code is not to declare variables of particular concrete classes' objects. Instead, use only an interface defined by a protocol or an abstract class. You will see this notion and theme throughout this book.

@protocol vs. Abstract Base Class (ABC)

So it's better to program to an interface, not an implementation. But what kind of interface should it be? In Objective-C, you can use a language feature called protocol (@protocol as its syntax). A protocol doesn't define any implementation; instead it only declares methods that determine how conforming classes should behave. So a protocol is an "interface" that only defines abstract behavior. Classes that implement the protocol define actual implementation for those methods to perform real operations. Another way to define a high-level abstract type is to define an abstract base class (ABC). With an abstract base class, you can create some default behavior that other subclasses can share. An abstract base class is like other regular classes but it leaves out some behavior that can or should be overridden by subclasses.

If you decide to change a protocol that you have defined in the past, you will probably break the other classes that implement it. A protocol (or an interface) is like a contract between an abstract type and concrete types. When the contract changes, everything that follows needs to change as well. The only exception is when you only change some of the protocol methods to become "optional" with a @optional directive. An abstract base class, on the other hand, is little more flexible than protocol in terms of interface changes. You are free to add new methods to an abstract base class without breaking the rest of the inheritance chain. Also, you can freely add, remove, or factor default behavior in some stubbed-out methods that could be used by subclasses.

For clients that want to use objects of the type defined in a protocol, let's say you have a protocol called Mark, and the clients need to refer any object of that kind with the following syntax:

id <Mark> thisMark;

If Mark is declared as an abstract base class, then the syntax should be just like other classes, like so:

Mark *thisMark;

In a method that accepts a Mark protocol object as a parameter, it would look like this:

- (void) anOperationWithMark:(id <Mark>) aMark;

Likewise, for a Mark abstract base class it goes like this:

- (void) anOperationWithMark:(Mark *) aMark;

Which one looks better? It's apparent that the Mark protocol reference seems a little awkward to use. Then why should you still keep protocols around anyway? One of the main reasons is that Objective-C is unlike other object-oriented languages, such as C++, that support multiple-inheritance. So if one of your classes needs to be a subclass of UIView, but at the same time it also needs to be a custom abstract type of yours, then you definitely need that abstract type to be a protocol rather than an abstract base class. For classes that don't need to subclass another class other than your abstract type, you can let them subclass your abstract base class directly.

But perhaps you might change the design later to support classes of your abstract type that can also be subclasses of, for example, UIView. Can you have the best of both world? A flexible solution for this situation in general is first to have an abstract base class for classes that don't need to subclass other classes, and then you can later define a protocol of the same name for other classes to implement including your abstract base class. You can find a similar strategy in the Cocoa Touch framework in which NSObject base class conforms to NSObject protocol.

Object Composition vs. Class Inheritance

Class inheritance or subclassing allows you to define an implementation of a class in terms of another's. Subclassing is often referred to as white-box reuse because the internal representation and details of parent classes are often visible to subclasses.

Object composition is an alternative to class inheritance. Object composition requires that the objects being composed have well-defined interfaces and that they are defined dynamically at runtime through references acquired by other objects. So you can compose objects within other ones to create more complex functionality. Since no internal details of objects are visible to others, they appear as "black boxes" and this style of reuse is called black-box reuse.

Both white-box and black-box reuses with class inheritance and object composition have their advantages and disadvantages. Some of the pros and cons about class inheritance are summarized next.

Pros:

  • Class inheritance is straightforward to use because the relationship is defined statically at compile-time.

  • It makes it easier to modify the implementation being reused.

Cons:

  • Because class inheritance is defined at compile-time, you can't change the inherited implementations from parent classes at runtime.

  • Part of the representation in subclasses is often defined in parent classes.

  • Subclasses are exposed to details of parent classes' implementation, so it breaks encapsulation.

  • Any change in the parent's implementation will force its subclasses to change as well because their implementations are so tied up together.

  • You need to rewrite the parent class or the inherited implementation because the inherited implementation becomes obsolete or inappropriate for new problem contexts.

Reusing a subclass can be problematic due implementation dependencies. One solution for this is to inherit (subtype) only from protocol(s) or abstract (base) class(es), as they usually have little or, in a protocol, no implementation.

Object composition lets you use one object with many others as each expects the others' interfaces to work. For this reason, they require carefully designed interfaces to make them work properly in a system. However, object composition also has some pros and cons to consider.

Pros:

  • You don't break encapsulation because objects are now accessed only through their interfaces.

  • There are substantially fewer implementation dependencies, as the object's implementation is defined in terms of the interfaces.

  • You can replace any object at runtime with another of the same type.

  • It helps keep a class encapsulated so it can focus on one task.

  • Your classes and their hierarchies will remain small. They will be less likely to grow into something unmanageable.

Cons:

  • The design will tend to have more objects.

  • The behavior of the system will depend on the relationships of different objects instead of being defined in one class.

  • Ideally, there is no need to create new components to achieve reuse. It is quite rare that you should be able to get all the functionality you need just by assembling existing components through object composition. In practice, the set of available components is never quite rich enough.

Despites the cons, object composition can provide many benefits on system design. Those cons can be counter-balanced by using class inheritance in certain areas as it helps make it easier to make new components from old ones.

So when you favor object composition over class inheritance, it doesn't mean that you shouldn't use class inheritance at all. You need to make a clear judgment on how to reuse classes and objects in certain situations. Class inheritance and object composition can work together if you design them properly for your systems. A natural way to think before you design a class is more towards object composition. You can then refine the design by looking for redundant behavior; if found, it may be a sign that's begging for class inheritance there. You will see object composition in the design patterns discussed in this book.

Objects and Classes Used in this Book

I use different diagrams and graphics in the book to illustrate some important ideas of the patterns. Sometimes I'll use screenshots or other visual representation to showcase, for example, the structure of a composite tree object. But I needed something more formal and clear to denote relationships and interactions between classes and objects alike. Most commonly used notations throughout the patterns in the book are class and object diagrams. I borrowed the OMT (Object Modeling Technique) notation and modified it to fit my needs. This section is going to describe the notations used for class and object diagrams.

Class Diagram

A class diagram illustrates classes, the static relationships between them, and their structure. In Objective-C, you can define a protocol, (abstract) class, and a category in your applications.

Protocol, Abstract Class, Concrete Class, and Category

In general, a round rectangular box denotes a class entity with its name in bold type at the top and operation names in the lower part of the box. If you are reading an electronic version of this book, you'll see that the background color of the protocol's title bar is pink and the other class entities' title bars have a light blue background. Names for abstract anything are in italics. So a protocol and an abstract class appear in bold and italics. A protocol name is enclosed in a pair of angle brackets. Instance variables are put in the very bottom part of the box. Samples of different class entities are illustrated in Figure 1-2.

A protocol with abstract operations on the left; an abstract class with both abstract and concrete operations at the center; and a concrete class with a concrete operation, concrete property, and an instance variable on the right

Figure 1-2. A protocol with abstract operations on the left; an abstract class with both abstract and concrete operations at the center; and a concrete class with a concrete operation, concrete property, and an instance variable on the right

Denoting a category is a little tricky because the original OMT doesn't support category as of this writing. A category is an extension of a class, but is not a subclass of that class. So it might be been confusing if I used arrows to illustrate the relationship. I've come up with the notation of augmenting a class box as shown in Figure 1-3.

The original class is on the right and its category is augmented on the right.

Figure 1-3. The original class is on the right and its category is augmented on the right.

The original class box is on the left and there's a similar rectangular box attached to it. The category name is enclosed in parenthesis and its augmented operations are put in the lower part of the box just like other classes. This notation may not be the most flexible notation especially if you have 100 categories in your design. But it is good enough for the illustrations used in this book.

In a class or object diagram, there can be some other roles that are part of the design. Those roles could be an abstract entity, such as a client, or some other classes within or outside the scope of the design. A grayed out round rectangular box denotes an implicit role that is part of an interaction but isn't essential to the discussion. Otherwise, a participant class will be denoted as round rectangle with a solid black border. If this is an ebook, the background color of a participant class box is light blue while the implicit one's background is clear or white (see Figure 1-4).

An implicit class on the left and a participating class on the right

Figure 1-4. An implicit class on the left and a participating class on the right

Instantiation

When I want to illustrate a class creating another class, I use a dashed line with an arrowhead to indicate that relationship. This is called the "creates" relationship. The arrow points to the class that is instantiated, as shown in Figure 1-5.

A class instantiates another class.

Figure 1-5. A class instantiates another class.

Inheritance

The OMT notation for class inheritance is a hollow triangle connecting a subclass to its parent class. Figure 1-6 shows this type of relationship with ConcreteClass being a subclass pointing its inheritance arrow to its parent class, AbstractClass. For interface inheritance (subtyping or conformance), I use a similar type of arrow to denote that kind of relationship but the arrowhead is associated with a dashed line instead. Figure 1-6 illustrates that kind of relationship also.

On the left, a concrete class inherits an abstract class to show a class inheritance relationship. On the right, a class subtypes (conforms to) a protocol to show an interface inheritance relationship.

Figure 1-6. On the left, a concrete class inherits an abstract class to show a class inheritance relationship. On the right, a class subtypes (conforms to) a protocol to show an interface inheritance relationship.

Acquaintance

I use a solid arrow pointing from a class to another to indicate an acquaintance relationship. This relationship and the other one called aggregation are crucial to the object composition principle (I'll talk about aggregation next). Figure 1-7 shows the relationship in that ConcreteClass has a reference to an AnotherClass object, but it doesn't "own" the life of the AnotherClass object and the reference can be shared by other objects. Or simply, ConcreteClass "knows" AnotherClass.

ConcreteClass forms an acquaintance relationship with AnotherClass.

Figure 1-7. ConcreteClass forms an acquaintance relationship with AnotherClass.

Aggregation

Like the acquaintance relationship, I use an arrow to indicate a reference to another object except that there is a diamond at the base of the arrow. But the relationship of the reference is somewhat different. Figure 1-8 shows that ConcreteClass has an aggregation relationship with AnotherClass. ConcreteClass owns AnotherClass as part of ConcreteClass, so both ConcreteClass and AnotherClass are an aggregate. The diagram of the figure also demonstrates another attribute of a reference. I use a double-headed arrow to mean "more than one." So, in the case of ConcreteClass, it contains multiple instances of AnotherClass as instanceVariable_.

ConcreteClass forms an aggregation relationship with multiple references to AnotherClass.

Figure 1-8. ConcreteClass forms an aggregation relationship with multiple references to AnotherClass.

Pseudocode

Sometimes a pattern can be better illustrated with pseudocode to sketch out the implementations of some operations. The body of a pseudocode annotation is put in a rectangular, dog-eared note box, as shown in Figure 1-9.

Pseudocode annotation

Figure 1-9. Pseudocode annotation

Object Diagram

An object diagram is only used for showing relationships between objects. It provides an idea of how objects can interconnect with each other in a design pattern. The names of objects are using a format of "aSomeClass" where SomeClass is the class of the object. A symbol for an object is very similar to one used for class diagrams. Each object is put in a round rectangular box with two compartments separating the object name from its object references. The background of the title bar of an object is also light blue in color. Solid arrows with a round circle base are used for pointing to the other objects being referenced. Figure 1-10 shows a sample object diagram.

An object diagram shows arrows with a round circle base indicating object references from an aClass object.

Figure 1-10. An object diagram shows arrows with a round circle base indicating object references from an aClass object.

How the Patterns are Organized

This edition covers 21 design patterns. They are organized into eight functional parts based on their practical themes or domains of usage: Object Creation, Interface Adaptation, Decoupling of Objects, Abstract Collection, Behavioral Extension, Algorithm Encapsulation, Performance and Object Access, and State of Object.

Summary

I've introduced the background, history, and benefits of design patterns as well as issues that would affect the architectural design of an application. I do hope that this chapter has been a good warm-up for the real flesh in the upcoming chapters.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.142.85