Foreword
Thanks to those of you who take the time to read through the article. If you feel like dropping off a vote (and particularly if it's a low one), please include a comment which mentions what the problem was. I've been getting mostly high votes for this article, apart from the odd 1's or 2's, and I'd really like to know what bothered those voters the most. Feedback is what drives improvement.
This article assumes you are familiar with object aspects of the JavaScript language. If not, it is recommended that you read the first half of Salvatore Vetro's article.
This article is organized as follows:
Problem
Graphic content is the thing every web developer deals with in every single page created. Problems begin when it goes a little further than placing an <IMG>
tag. You may wish to build a web-based graphics editor, game, ad banner, interactive teaser, etc.
The first solution that comes to mind is Flash. You can satisfy almost any web graphics need with it, but disadvantages can be prohibitive. They are: need for investments in docs, tools, and programmers; deficient support for in-browser scripting; incompatibility with numerous web media standards, problems with Flash Player security; etc.
XML-based standards are the alternative. They offer perfect web integration (as XML does), are extensible, and do not require downloading large binary archives. The only drawback is that XML is 'still' an emerging technology, so you'll meet numerous incompatibility issues when dealing with XML grammars.
To start with web graphics, we'll need something simple like this:
<script type="text/javascript">
var vgr = new VectorGraphics(...);
vgr.MoveTo(100, 100);
vgr.Rect(100, 100, "#0F0");
vgr.MoveTo(350, 350);
vgr.Circle(50, "#F0F");
...
</script>
As usual, there is more than one way to do the job. To be exact, the number of ways is the number of browsers, plug-ins, and standards (cross-multiplied with each other...) on the web. To satisfy the needs of all (or, at least, the majority of) your customers, you must pass all these ways... Do you want to meet the multiple-page-browser-and-platform-detection-stuff (with all those switches and if
s so easy to get lost in) once again? I don't.
So, before we move on with rectangles and circles, we'll have to answer two not-so-simple questions:
- how do we build an object library which will take the best of two (three, four...) worlds, if choices are available?
- how do we build an object library which is easy to extend and maintain?
The answer is:
Bridge pattern
Note: JavaScript is a prototype-based language, and doesn't support many features common to object-oriented languages. Where it makes sense, I'll make notes describing differences and sideways; they are designated as [JavaScript].
-
Motivation
Consider the implementation of a cross-browser vector graphics library. Its main purpose is to allow us to use an (X)HTML page as a painting canvas, so we can draw various shapes: lines, rectangles, circles, etc. It also should enable us to write scripts that work on any browser that supports either SVG or VML standards. Using inheritance ([JavaScript]: prototype chaining), we could define an interface
VectorGraphics
, and classesVectorGraphicsImplSVG
andVectorGraphicsImplVML
that implement the given interface:This approach has two problems:
- It is inconvenient to extend the
VectorGraphics
abstraction to cover more specialized kinds of vector graphics API, or new platforms. Imagine aGeoGraphics
subclass ofVectorGraphics
that specializes the vector graphics to display GIS data. To supportGeoGraphics
for both SVG and VML user agents, we have to implement two new classes,GeoGraphicsImplSVG
andGeoGraphicsImplVML
. Worse, we'll have to define two classes for every new XML-based graphics standard. Supporting a third API requires yet another new vector graphics subclass for every specific case ofVectorGraphics
. Every framework extension leads to the explosive growth of class/prototype hierarchy: - Once the supporting programmer has
GeoGraphicsImplSVG
andGeoGraphicsImplVML
, what class should he/she instantiate? It is clear that theVectorGraphics
class itself must "decide" what class to present to the end-user. In other words, clients should be able to instantiate aVectorGraphics
object without committing to a concrete implementation. Only the implementation classes should depend on the platform on which the script runs. Therefore, client code should instantiateVectorGraphics
without mentioning specific graphics standards.
The Bridge pattern solves the problem by putting the
VectorGraphics
abstraction and all its implementations in separate class/prototype hierarchies. There is one hierarchy forVectorGraphics
interfaces (VectorGraphics
,GeoGraphics
,UIGraphics
), and a separate hierarchy for platform-specific implementations, withVectorGraphicsImpl
as its root (see details below). TheVectorGraphicsImplSVG
, for example, provides an implementation based on the SVG rendering subsystem.Such a relationship between
VectorGraphics
andVectorGraphicsImpl
is called a bridge, because it bridges the interface and its implementation, letting them vary independently.(C++ gurus can say: "bridge pattern adds one 'level of indirection', just like a Proxy pattern".)
- It is inconvenient to extend the
-
Applicability
Use the Bridge pattern when:
- you want to explicitly separate the interface and the implementation for a custom object. This allows you to choose (and even switch) implementors at run-time
- both the abstractions and their implementations should be extensible (by either subclassing or prototype chaining). This prevents the uncontrolled growth of class hierarchy, and allows you to evade cumulative coding errors (changes on the implementor classes have no impact on the interface classes). That is why the Bridge pattern is great when used as a base of cross-platform frameworks
- you want to localize platform-specific code, thus making your scripts easy to extend and maintain
- you want to localize browser/feature/object detection code. (Note: you may or may not want to do it; the structure of the bridge pattern forces you to do it.)
-
Structure
-
Participants
-
Abstraction
- defines the abstraction's interface
- maintains a reference to an implementor object
-
RefinedAbstraction
- extends the interface defined by abstraction
-
Implementor
- defines the interface for implementation classes. This interface may or may not be the same as the abstraction's.
Note: since JavaScript is a loosely-typed language with no notion of abstract classes,
Implementor
is uncommon to JavaScript implementations of the Bridge pattern. It is usual to have a set ofConcreteImplementors
; you set or change theabstraction
's implementor reference to one of theConcreteImplementors
during the setup of the bridge. AllConcreteImplementors
must conform to a chosen interface, as if all concrete implementors were subclasses of anImplementor
. ConcreteImplementor
- implements the
Implementor
interface and defines its concrete implementation.
- implements the
-
-
Collaborations
The abstraction forwards client requests to its
Implementor
object.
Комментариев нет:
Отправить комментарий