Implementation of design patterns with C ++-legends of two iterators

Source: Internet
Author: User

Introduction

In an object-oriented system, design patterns are reusable data structures that become the central topic of Gamma's design patterns book. In this article, I will

Explain the principles of the design patterns, and I will compare the iterator design patterns described in the Gamma book with those implemented in the standard template library.

 

Historical summary of design patterns

In the early days of Object-oriented Programs, object models were almost considered to have created a new era of code design and reuse. With the development of science and technology, reality is more complex than propaganda.

Miscellaneous, the object-oriented subject is a powerful tool, but it cannot lead to good software design, just as bricks and ash cannot lead to good architectural design.

In the object-oriented system design, it is not enough to understand the object model. How is an object created? How are they initialized? Who owns the object instance

? How to access the object instance? Who is responsible for object destruction?

The design pattern can be used to answer these questions. The design pattern depicts the relationship of Object reuse. Similarly, the design pattern is an object-oriented program, and the algorithm is structured.

The basic elements of a program or structured program (ordered command, condition, and branch) do not contain the concepts of a structure such as a linked list and a quick query, so it is not very effective.

But what is the design pattern?

Consider a bitmap class. Suppose you want this bitmap class to support multiple image file formats (GIF, JPG, BMP, etc). One way is for each

File types to add a member function:

Class bitmap
{
Public:
Void readbmp (const char * filename );
Void readjpg (const char * filename );
Void readgif (const char * filename );
...
};

This method has many disadvantages. First, with the support for a large number of file formats, the interface becomes increasingly chaotic. To support new file formats, You need to modify the bitmap class.

So this is difficult and undesirable. If you want bitmap to support an application file format, modifying bitmap to support this format will pollute the interface.

A better way to solve this problem is to separate the file part from the class, which requires defining the second class:

Class bitmapbuilder
{
Public:
Virtual void readfromfile (Bitmap *,
Const char * filename) = 0;
};

 

To support the new file format, all you need to do is inherit the bitampbuilder class and implement the readfromfile () function. jpgbuilder reads JPG files,

BMP builder reads BMP files. Now you can implement the new file format and private file format without modifying the bitmap interface.

This concept, that is, the concept of an interface that separates classes from an initialized interface, is the builder design mode.

Of course, this pattern already exists before gamma and other people attach the "Builder" name. However, adding such a simple name to a complex concept helps us

It has developed a powerful vocabulary for Object design.

In addition, the structure of builder helps us to realize that the problem of supporting multiple file formats can be applied to such a type of problem, and create a new

Word processing documentation, or create a random maze design for the game.

Adding "Builder" to the object structure is similar to adding a "quicksort" name to the O (nlog (N) divide-and-conquer query algorithm. Every time you

You do not need to explain it when using it.

 

Design Mode and C ++

In their books, gamma and others restricted them to traditional object-oriented languages, naming inheritance and virtual functions, which are powerful tools.

It is not a tool used by C ++ programmers,

To illustrate how the traditional object-oriented language and C ++ language can achieve the same goal, I will compare the description and standard of the Design Pattern of the iterator in the Gamma book.

The iterator provided by the quasi-template library.

 

Iterator Design Mode

Research a container that can implement multiple containers (list, vector, binary number, etc.), the Container inherits from an abstract container class.

 

Template <class item>
Class container
{
Public:
Void additem (const item & item) = 0;
Void removeitem (const item & item) = 0;
};

Lists, vectors, queues, trees, and so on are inherited from the container class, And the additem () and removeitem () methods are implemented.

If you want the client to access the elements of these container classes, but you do not know which container to use, the iterator design pattern is as described in the book, with inheritance

And virtual functions provide a way to solve this problem. The second object type is used to provide access to elements in the container.

The abstract iterator class accesses the elements of the container by defining the client interface.

Template <class item>
Class iterator
{
Public:
Virtual item & currentitem () = 0;
Virtual void gotofirst () = 0;
Virtual void gotonext () = 0;
Virtual bool isdone () = 0;
};

 

Currentitem () returns the current entry pointed to by the iterator. gotofirst () sets the iterator to point to the starting position of the container, and gotonext () sets the iterator to point to the container

If the iterator points to the last element in the container, isdone () returns true.

The specific iterator of each container is inherited from the iterator. Listiterator, vectoriterator, treeiterator, dequeiterator, and so on.

Their respective containers implement the iterator interface.

Since the client does not need to know the specific container they are using, they do not need to know what type of iterator they are creating. To solve this problem, we provide

Add a createiterator () function.

 

Template <class item>
Class container
{
Public:
Iterator <item> * createiterator () = 0;
...
};

 

 

The specific container implements createiterator () and returns the correct iterator type.

 

Template <class item>
Class list: public container <item>
{
Public:
Iterator <item> * createiterator ()
{
Return new listiterator <item> ();
}
...
};

So how can we use these iterators? A function used to print every element in the container looks like the following.

 

Template <class item>
Void printelements (container <item> * container)
{
Iterator <item> * It = container-> createiterator ();
It-> gotofirst ();
While (! It-> isdone ())
{
Cout <it-> currentitem () <Endl;
It-> gotonext ();
}
Delete it;
}

This method is very effective. It enables you to use the printelements () function only once in any container. It also has some disadvantages. First, in the future

Each newly added client must inherit printelements () from the iner. Second, printelements () enables the three virtual functions to be called cyclically within it. Image Printing

This kind of program may not have much influence, but a large number of loops may have problems.

It is even more satisfactory to protect the universal features of this implementation, but at the same time reduce the burden on the Structure and execution of our programs.

 

STL iterators

 

STL iterators provides general sequential access for their containers, but does not need virtual functions or inheritance at the same time. How can this problem be solved? C ++ implements the STL principle. In fact

In C, the iterator has already been compiled into the language. They are called pointers.

Think about the following C ++ functions:

Template <class item>
Void printarray (item * array, size_t Len)
{
Item * It = & array [0];
While (it! = & Array [Len])
{
Cout <* It <Endl;
++ It;
}
}

 

This function has the same effect as the printelements () function described in the previous section. "iterator" is added at the beginning of the array until it extends to the end of the array.

Tail. However, this printelements () does not use virtual functions and does not require users to inherit from any place.

The only problem is that it only works for the built-in array. This method cannot work for the linked list or binary near tree, isn't it?

Usually, the object-oriented design raises the concept of the underlying machine (like pointers and arrays) to a higher level, just like containers and iterators, but STL iterator uses

In the opposite way, STL iterators uses the re-planting operation to achieve the same behavior at a high level as the built-in pointer. ++ And -- operations are used to move to the next or

Use the * operation to access the data of the previous element.

The printelements () version of STL looks like the following:

Template <class iterator>
Void printelements (iterator first, iterator last)
{
While (first! = Last)
{
Cout <* First <Endl;
&

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.