esign Patterns:Elements of Rousable Object-Oriented Software ClassName ion2() Return types and instance variable types are optional,since we don't assume a statically typed implementation language obiects are created by instantiating a class.The obiect is said to be an instance of the ciass.The object's internal data (made up of instance variables)and associates the operations with these data.Many similar instances of an object can be created by instantiating a class. A dashed arrowhead line indicates a class that instantiates objects of another c1a53. The arrow points to the class of the instantiated objects Instantiator -一Instantiatee New classes can be defined in terms of existing classes using class inheritance When a subclass inherits from a parent class,it includes the definitions of all the data and operations that the parent class defines.Objects that are instancea of the defined by the aub and its parent clas and they'11 be able to perform all operations defined by this subclass and its parents.We indicate the subelass relationship with a vertical line and a triangle: ParentClass Operation( An abstract class is one whose main p rpose is to define n interface for class wi defer some or all of its to operations defined in subclasses;hence an abstract class cannot be instantiated 27
Design Patterns: Elements of Reusable Object-Oriented Software 27 Return types and instance variable types are optional, since we don't assume a statically typed implementation language. Objects are created by instantiating a class. The object is said to be an instance of the class. The process of instantiating a class allocates storage for the object's internal data (made up of instance variables) and associates the operations with these data. Many similar instances of an object can be created by instantiating a class. A dashed arrowhead line indicates a class that instantiates objects of another class. The arrow points to the class of the instantiated objects. New classes can be defined in terms of existing classes using class inheritance. When a subclass inherits from a parent class, it includes the definitions of all the data and operations that the parent class defines. Objects that are instances of the subclass will contain all data defined by the subclass and its parent classes, and they'll be able to perform all operations defined by this subclass and its parents. We indicate the subclass relationship with a vertical line and a triangle: An abstract class is one whose main purpose is to define a common interface for its subclasses. An abstract class will defer some or all of its implementation to operations defined in subclasses; hence an abstract class cannot be instantiated
Design Patterns:Elemente of Reusable Object-Oriented Software The operations that an abstract class declares but doesn't implement are called abstract operations.classes that aren't abstract are called concrete classes. Subclasses can refine and redefine behaviors of their parent classes.More specifically,a class may override an operation defined by its parent class overriding gives subclasses a chance to handle requests instead of their parent classes.class inheritance lets vou define classes simply by extending other classes,making it easy to define families of obiects having related functionality. The names of abstract classes appear in slanted type to distinguish them from concrete c es used to denote abstrac ratic ns diagram may include pseudocode for an operation's implementation;if so,the code will appear in a dog-eared box connected by a dashed line to the operation it implements. Operation( ConcreteSubclass Operaton()---- A mixin class is a class that's intended to provide an optional interface or functionality to other classes.It's similar to an abstract class in that it's not intended to be instantiated.Mixin classes require multiple inheritance: ExistingClass Mixin ExistingOperation( 28
Design Patterns: Elements of Reusable Object-Oriented Software 28 The operations that an abstract class declares but doesn't implement are called abstract operations. Classes that aren't abstract are called concrete classes. Subclasses can refine and redefine behaviors of their parent classes. More specifically, a class may override an operation defined by its parent class. Overriding gives subclasses a chance to handle requests instead of their parent classes. Class inheritance lets you define classes simply by extending other classes, making it easy to define families of objects having related functionality. The names of abstract classes appear in slanted type to distinguish them from concrete classes. Slanted type is also used to denote abstract operations. A diagram may include pseudocode for an operation's implementation; if so, the code will appear in a dog-eared box connected by a dashed line to the operation it implements. A mixin class is a class that's intended to provide an optional interface or functionality to other classes. It's similar to an abstract class in that it's not intended to be instantiated. Mixin classes require multiple inheritance:
Design Patterns:Elements of Rousable Object-Oriented Software Class versus Interface Inheritance It's important to understand the difference between an object's class and its type. An oblect's class defines how the oblect is implemented.The class defines the object's internal state and the implementation of its operations.In contrast, an obiect's type only refers to its interface-the set of reguesta to which it can spond.An object can have many types, and objects of different classes can have the same type Of course,there's a close relationship between class and type.Because a class defines the operations an obiect can pertorm,it also defines the obiect's type. When we say that an obiect is an instance of a class,we imply that the obiect supports the interface defined by the class. Languages like C++ and Eiffel use classes to specify both an object's type and its implementation.Smalltalk programs do not declare the types of variables; consequently,the compiler does not check that the types of objects assigned to a variable are subtypes of the variable's type.sending a message reguires checking that the class of the receiver implements the message,but it doesn't require checking that the receiver is an instance of a particular class It's also tant to u the difference between class inheritance and interface inheritance (or subtyping).class inheritance defines an object's implementation in terms of another object's implementation.In short,it's a mechanism for code and representation sharing.In contrast.interface inheritance (or subtyping)describes when an object can be used in place of another. It'easy to confuse these two concepts,because many languages don't make the distinction e C++and Eitrel,inheritanc both interface and implementation inheritance.The standard way to inherit an interface in C++is to inherit publicly from a class that has (pure)virtual member functions. Pure interface inheritance can be approximated in C++by inheriting publicly from pure abstract classes.Pure implementation or class inheritance can be ivate imheritance.In allalk,inheritance meansu implementation inheritance.You can assign instances of any class to a variable as long as those instances support the operation performed on the value of the variable. Although most programming languages don't support the distinction between interface and implementation inheritance,people make the distinction in practice. usually act t as ir sube lasses were subtypes (though there 29
Design Patterns: Elements of Reusable Object-Oriented Software 29 Class versus Interface Inheritance It's important to understand the difference between an object's class and its type. An object's class defines how the object is implemented. The class defines the object's internal state and the implementation of its operations. In contrast, an object's type only refers to its interface—the set of requests to which it can respond. An object can have many types, and objects of different classes can have the same type. Of course, there's a close relationship between class and type. Because a class defines the operations an object can perform, it also defines the object's type. When we say that an object is an instance of a class, we imply that the object supports the interface defined by the class. Languages like C++ and Eiffel use classes to specify both an object's type and its implementation. Smalltalk programs do not declare the types of variables; consequently, the compiler does not check that the types of objects assigned to a variable are subtypes of the variable's type. Sending a message requires checking that the class of the receiver implements the message, but it doesn't require checking that the receiver is an instance of a particular class. It's also important to understand the difference between class inheritance and interface inheritance (or subtyping). Class inheritance defines an object's implementation in terms of another object's implementation. In short, it's a mechanism for code and representation sharing. In contrast, interface inheritance (or subtyping) describes when an object can be used in place of another. It's easy to confuse these two concepts, because many languages don't make the distinction explicit. In languages like C++ and Eiffel, inheritance means both interface and implementation inheritance. The standard way to inherit an interface in C++ is to inherit publicly from a class that has (pure) virtual member functions. Pure interface inheritance can be approximated in C++ by inheriting publicly from pure abstract classes. Pure implementation or class inheritance can be approximated with private inheritance. In Smalltalk, inheritance means just implementation inheritance. You can assign instances of any class to a variable as long as those instances support the operation performed on the value of the variable. Although most programming languages don't support the distinction between interface and implementation inheritance, people make the distinction in practice. Smalltalk programmers usually act as if subclasses were subtypes (though there
Design Patterns:Elements of Rousable Object-Orionted Software are some well-known exceptions [Coo92]);C++programmers manipulate objects through types defined by abstract classes Many of the design patterns depend on this distinction.For example,objects in a Chain of Responsibility (251)must have a common type,but usually they don't share a common implementation.In the Composite (183)pattern,Component defines a common interface.but Composite often defines a common implementation.Command (263),Observer (326),State (338),and Strategy (349)are often implemented with abstract classes that are pure interfaces. Programming to an Interface,not an Implementation class inheritance is basically just a mechanism for extending an application's functionality by reusing functionality in parent classes.It lets you define a new kind of object rapidly in terms of an old one.It lets you get new implementations almost for free,inheriting most of what you need from existing classes However,implementation reuse is only halr the story.Inheritance's ability to detine families of objects with identical interfaces(usually by inheriting from an abstract class)is also important.Why?Because polymorphism depends on it. When inheritance is used carefully (some will say properly),all classes derived from an abstract class will share its interface.This implies that a subclass rations of the parent A11 ses can ond to t the interfac e of thi abstract class,making them all subtypes of the abstract class There are two benefits to manipulating objects solely in terms of the interface defined by abstract classes: 1.clients remain unaware of the specific types of objects they use,as long as the objects adhere to the interface that clients expect of the cla at h ese objects.clients only know about the abstract class(es)defining the interrace This so greatly reduces implementation dependencies between aubsystems that it leads to the following principle of reusable object-oriented design: Program to an interface,not an implementation Don't declare variables to be instances of particular concrete classes.Instead, mmit only to an interface derined by an abstract class.You will tind this to be a common theme of the design patterns in this book 30
Design Patterns: Elements of Reusable Object-Oriented Software 30 are some well-known exceptions [Coo92]); C++ programmers manipulate objects through types defined by abstract classes. Many of the design patterns depend on this distinction. For example, objects in a Chain of Responsibility (251) must have a common type, but usually they don't share a common implementation. In the Composite (183) pattern, Component defines a common interface, but Composite often defines a common implementation. Command (263), Observer (326), State (338), and Strategy (349) are often implemented with abstract classes that are pure interfaces. Programming to an Interface, not an Implementation Class inheritance is basically just a mechanism for extending an application's functionality by reusing functionality in parent classes. It lets you define a new kind of object rapidly in terms of an old one. It lets you get new implementations almost for free, inheriting most of what you need from existing classes. However, implementation reuse is only half the story. Inheritance's ability to define families of objects with identical interfaces (usually by inheriting from an abstract class) is also important. Why? Because polymorphism depends on it. When inheritance is used carefully (some will say properly), all classes derived from an abstract class will share its interface. This implies that a subclass merely adds or overrides operations and does not hide operations of the parent class. All subclasses can then respond to the requests in the interface of this abstract class, making them all subtypes of the abstract class. There are two benefits to manipulating objects solely in terms of the interface defined by abstract classes: 1. Clients remain unaware of the specific types of objects they use, as long as the objects adhere to the interface that clients expect. 2. Clients remain unaware of the classes that implement these objects. Clients only know about the abstract class(es) defining the interface. This so greatly reduces implementation dependencies between subsystems that it leads to the following principle of reusable object-oriented design: Program to an interface, not an implementation. Don't declare variables to be instances of particular concrete classes. Instead, commit only to an interface defined by an abstract class. You will find this to be a common theme of the design patterns in this book
Design Patterns:Elements of Rousable Object-Oriented Software You have to instantiate concrete classes (that is,specify a particular implementation)somewhere in your system,of course,and the e creational patterns (Abstract Factory (99),Builder (110),Factory Method (121),Prototype (133) and Singleton (144)let you do iust that.By abstracting the process of obiect creation,these patterns give you different ways to associate an interface with its implementation transparently at instantiation.Creational patterns ensure that your in terms of interfaces not impler ntations Putting Reuse Mechanisms to Work Most people can understand concepts like objects,interfaces,classes,and inheritance.The challenge lies in applying them to build flexible,reusable software,and design patterns can show you how. Inheritance versus Composition The two most common techniques for reusing functionality in object-oriented systems are class inheritance and object composition.As we've explained,class inheritance lets you define the implementation of one class in terms of another's. Reuse by subclassing is often referred to as white-box reuse.The term "white-box" cefers to visibility:with inheritance,the internals of parent classes are often visible to subclasses. Object composition is an alternative to class inheritance.Here,new functionality is obtained by assembling or composing objects to get more complex functionality. Object composition requires that the objects being composed have well-defined interfaces.This style of reuse is called black-box reuse,because no internal details of obiects a are visible.Objects appear only as "black boxes." sition each have their advantac s and disadva inheritance is defined statically at compile-time and is straightforward to use since it's supported directly by the programming language.Class inheritance also makes it easier to modify the implementation being reused.When a subclass overrides some but not all operations,it can atfect the operations it inherits as well,assuming they call the overridden operations But class e has some disadvantages,too.First,you can't change the implementations inherited from parent classes at run-time,because inheritance is defined at compile-time.Second,and generally worse,parent classes often define at least part of their subclasses'physical representation.Because inheritance exposes a subclass to details of its parent's implementation,it's often said that "inheritance breaks encapsulation"[Sny86].The implementatior Lass becomes so bound up with the implem its parent clasa that any change in the parent's implementation will force the subclass to change. 31
Design Patterns: Elements of Reusable Object-Oriented Software 31 You have to instantiate concrete classes (that is, specify a particular implementation) somewhere in your system, of course, and the creational patterns (Abstract Factory (99), Builder (110), Factory Method (121), Prototype (133), and Singleton (144) let you do just that. By abstracting the process of object creation, these patterns give you different ways to associate an interface with its implementation transparently at instantiation. Creational patterns ensure that your system is written in terms of interfaces, not implementations. Putting Reuse Mechanisms to Work Most people can understand concepts like objects, interfaces, classes, and inheritance. The challenge lies in applying them to build flexible, reusable software, and design patterns can show you how. Inheritance versus Composition The two most common techniques for reusing functionality in object-oriented systems are class inheritance and object composition. As we've explained, class inheritance lets you define the implementation of one class in terms of another's. Reuse by subclassing is often referred to as white-box reuse. The term "white-box" refers to visibility: With inheritance, the internals of parent classes are often visible to subclasses. Object composition is an alternative to class inheritance. Here, new functionality is obtained by assembling or composing objects to get more complex functionality. Object composition requires that the objects being composed have well-defined interfaces. This style of reuse is called black-box reuse, because no internal details of objects are visible. Objects appear only as "black boxes." Inheritance and composition each have their advantages and disadvantages. Class inheritance is defined statically at compile-time and is straightforward to use, since it's supported directly by the programming language. Class inheritance also makes it easier to modify the implementation being reused. When a subclass overrides some but not all operations, it can affect the operations it inherits as well, assuming they call the overridden operations. But class inheritance has some disadvantages, too. First, you can't change the implementations inherited from parent classes at run-time, because inheritance is defined at compile-time. Second, and generally worse, parent classes often define at least part of their subclasses' physical representation. Because inheritance exposes a subclass to details of its parent's implementation, it's often said that "inheritance breaks encapsulation" [Sny86]. The implementation of a subclass becomes so bound up with the implementation of its parent class that any change in the parent's implementation will force the subclass to change