📄 chap1-1.htm
字号:
interface. The <A HREF="pat5ffs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5ffs.htm" TARGET="_mainDisplayFrame">Memento (283)</A> pattern is a good example.
It describes how to encapsulate and save the internal state of an
object so that the object can be restored to that state later. The
pattern stipulates that Memento objects must define two interfaces: a
restricted one that lets clients hold and copy mementos, and a
privileged one that only the original object can use to store and
retrieve state in the memento.</P>
<A NAME="auto1078"></A>
<P>Design patterns also specify relationships between interfaces. In
particular, they often require some classes to have similar
interfaces, or they place constraints on the interfaces of some
classes. For example, both <A HREF="pat4dfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4dfs.htm" TARGET="_mainDisplayFrame">Decorator (175)</A> and
<A HREF="pat4gfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4gfs.htm" TARGET="_mainDisplayFrame">Proxy (207</A>) require the interfaces of Decorator and Proxy
objects to be identical to the decorated and proxied objects. In
<A HREF="pat5kfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5kfs.htm" TARGET="_mainDisplayFrame">Visitor (331)</A>, the Visitor interface must reflect all
classes of objects that visitors can visit.</P>
<H3>Specifying Object Implementations</H3>
<A NAME="auto1079"></A>
<P>So far we've said little about how we actually define an object. An
object's implementation is defined by its <a href="chapAfs-1.htm#class" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#class" target="_mainDisplayFrame">class</A>. The class
specifies the object's internal data and representation and defines
the operations the object can perform.</P>
<A NAME="auto1080"></A>
<P>Our OMT-based notation (summarized in
<A HREF="chapBfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/chapBfs.htm" TARGET="_mainDisplayFrame">Appendix B</A>)
depicts a class as a rectangle with the class name in bold.
Operations appear in normal type below the class name. Any data that
the class defines comes after the operations. Lines separate the
class name from the operations and the operations from the data:</P>
<P ALIGN=CENTER><IMG SRC="class-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/class.gif"></P>
<A NAME="auto1081"></A>
<P>Return types and instance variable types are optional, since we don't
assume a statically typed implementation language.</P>
<A NAME="auto1082"></A>
<P>Objects are created by <STRONG>instantiating</STRONG> a class. The object
is said to be an <STRONG>instance</STRONG> of the class. The process of
instantiating a class allocates storage for the object's internal data
(made up of <a href="chapAfs-1.htm#instancevariable" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#instancevariable" target="_mainDisplayFrame">instance variables</a>) and associates the
operations with these data. Many similar instances of an object can be
created by instantiating a class.</P>
<A NAME="auto1083"></A>
<P>A dashed arrowhead line indicates a class that instantiates objects
of another class. The arrow points to the class of the instantiated
objects.</P>
<P ALIGN=CENTER><IMG SRC="insta045-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/insta045.gif"></P>
<A NAME="auto1084"></A>
<P>New classes can be defined in terms of existing classes using
<a href="chapAfs-1.htm#inheritance" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#inheritance" target="_mainDisplayFrame">class inheritance</a>. When a <a href="chapAfs-1.htm#subclass" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#subclass" target="_mainDisplayFrame">subclass</A> inherits
from a <a href="chapAfs-1.htm#superclass" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#superclass" target="_mainDisplayFrame">parent class</A>, 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:</P>
<P ALIGN=CENTER><IMG SRC="subcl009-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/subcl009.gif"></P>
<A NAME="abstractclass"></A>
<A NAME="abstractoper"></A>
<P>An <a href="chapAfs-1.htm#abstractclass" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#abstractclass" target="_mainDisplayFrame">abstract class</A> 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. The operations that an
abstract class declares but doesn't implement are called
<a href="chapAfs-1.htm#abstractoperation" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#abstractoperation" target="_mainDisplayFrame">abstract operations</a>. Classes that aren't abstract are
called <a href="chapAfs-1.htm#concreteclass" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#concreteclass" target="_mainDisplayFrame">concrete classes</a>.</P>
<A NAME="oper-override"></A>
<P>Subclasses can refine and redefine behaviors of their parent classes.
More specifically, a class may <a href="chapAfs-1.htm#overriding" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#overriding" target="_mainDisplayFrame">override</a> 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.</P>
<A NAME="pseudocode"></A>
<P>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.</P>
<A NAME="absclass"></A>
<A NAME="pseudocode-16c"></A>
<P ALIGN=CENTER><IMG SRC="absclass-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/absclass.gif"></P>
<A NAME="auto1085"></A>
<P>A <a href="chapAfs-1.htm#mixinclass" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#mixinclass" target="_mainDisplayFrame">mixin class</A> 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:</P>
<P ALIGN=CENTER><IMG SRC="mixin-1.gif" tppabs="http://ultra/development/DesignPatterns/lowres/Pictures/mixin.gif"></P>
<A NAME="type-vs-class"></A>
<H4>Class versus Interface Inheritance</H4>
<A NAME="auto1086"></A>
<P>It's important to understand the difference between an object's <a href="chapAfs-1.htm#class" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#class" TARGET="_mainDisplayFrame">class</A> and its <A HREF="chapAfs-1.htm#type" tppabs="http://ultra/development/DesignPatterns/lowres/chapAfs.htm#type" target="_mainDisplayFrame">type</A>.</P>
<A NAME="auto1087"></A>
<P>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.</P>
<A NAME="auto1088"></A>
<P>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.</P>
<A NAME="eiffel"></A>
<A NAME="type-def-in-cpp"></A>
<A NAME="type-def-in-eiffel"></A>
<A NAME="type-def-in-smalltk"></A>
<P>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.</P>
<A NAME="auto1089"></A>
<P>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.</P>
<A NAME="auto1090"></A>
<P>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.</P>
<A NAME="auto1091"></A>
<P>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 are some well-known
exceptions [<a href="bibfs-1.htm#cook92" tppabs="http://ultra/development/DesignPatterns/lowres/bibfs.htm#cook92" target="_mainDisplayFrame">Coo92</A>]); C++ programmers manipulate objects through
types defined by abstract classes.</P>
<A NAME="auto1092"></A>
<P>Many of the design patterns depend on this distinction. For example,
objects in a <A HREF="pat5afs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5afs.htm" TARGET="_mainDisplayFrame">Chain of Responsibility (223)</A> must have a
common type, but usually they don't share a common implementation. In
the <A HREF="pat4cfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat4cfs.htm" TARGET="_mainDisplayFrame">Composite (163)</A> pattern, Component defines a
common interface, but Composite often defines a common implementation.
<A HREF="pat5bfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5bfs.htm" TARGET="_mainDisplayFrame">Command (233)</A>, <A HREF="pat5gfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5gfs.htm" TARGET="_mainDisplayFrame">Observer (293)</A>,
<A HREF="pat5hfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5hfs.htm" TARGET="_mainDisplayFrame">State (305)</A>, and <A HREF="pat5ifs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat5ifs.htm" TARGET="_mainDisplayFrame">Strategy (315)</A> are often
implemented with abstract classes that are pure interfaces.</P>
<H4>Programming to an Interface, not an Implementation</H4>
<A NAME="auto1093"></A>
<P>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.</P>
<A NAME="poly-w-inherit"></A>
<A NAME="implement-reuse"></A>
<P>However, implementation reuse is only half the story. Inheritance's
ability to define families of objects with <EM>identical</EM> interfaces
(usually by inheriting from an abstract class) is also important. Why?
Because polymorphism depends on it.</P>
<A NAME="auto1094"></A>
<P>When inheritance is used carefully (some will say <EM>properly</EM>), 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. <EM>All</EM> subclasses
can then respond to the requests in the interface of this abstract
class, making them all subtypes of the abstract class.</P>
<A NAME="auto1095"></A>
<P>There are two benefits to manipulating objects solely in terms of the
interface defined by abstract classes:</P>
<OL>
<A NAME="auto1096"></A>
<LI>Clients remain unaware of the specific types of objects they use,
as long as the objects adhere to the interface that clients expect.</LI>
<A NAME="auto1097"></A>
<P></P>
<A NAME="auto1098"></A>
<LI>Clients remain unaware of the classes that implement these objects.
Clients only know about the abstract class(es) defining the interface.</LI>
</OL>
<A NAME="auto1099"></A>
<P>This so greatly reduces implementation dependencies between subsystems
that it leads to the following principle of reusable object-oriented
design:</P>
<BLOCKQUOTE>
<I>Program to an interface, not an implementation.</I>
</BLOCKQUOTE>
<A NAME="auto1100"></A>
<P>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.</P>
<A NAME="auto1101"></A>
<P>You have to instantiate concrete classes (that is, specify a
particular implementation) somewhere in your system, of course, and
the creational patterns (<A HREF="pat3afs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat3afs.htm" TARGET="_mainDisplayFrame">Abstract Factory (87)</A>,
<A HREF="pat3bfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat3bfs.htm" TARGET="_mainDisplayFrame">Builder (97)</A>, <A HREF="pat3cfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat3cfs.htm" TARGET="_mainDisplayFrame">Factory Method (107)</A>,
<A HREF="pat3dfs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat3dfs.htm" TARGET="_mainDisplayFrame">Prototype (117)</A>, and <A HREF="pat3efs-1.htm" tppabs="http://ultra/development/DesignPatterns/lowres/pat3ef
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -