본문 바로가기
James Cooper - Python Programming with D

The Prototype Pattern

by 자동매매 2023. 3. 23.

10**

The Prototype Pattern

The Prototype pattern is used when creating an instance of a class is very time consuming or complex in some way. Instead of creating more instances, you make copies of the original instance and modify the copies as appropriate.

Prototypes can also be used whenever you need classes that differ only in the type of processing they offer—for example, in parsing strings that represent numbers in different radixes.

Let’s consider the case of an extensive database in which you need to make a number of queries to construct an answer. When you have this answer as a table or ResultSet, you might want to manipulate it to produce other answers without issuing additional queries.

In a case like one we have been working on, let’s consider a database of a large number of swimmers in a league or statewide organization. Each swimmer swims several strokes and distances throughout a season. The best times for swimmers are tabulated by age group, and many swimmers have birthdays and move into new age groups within a single season. Thus, the query to determine which swimmers did the best in their age group that season is dependent on the date of each meet and on each swimmer’s birthday. The computational cost of assembling this table of times is therefore fairly high.

Once we have a class containing this table, sorted by sex, we might want to examine this information sorted just by time or just by actual age instead of by age group. It would not be sensible to recompute these data, and we do not want to destroy the original data order. Instead, we want some sort of copy of the data.

Cloning in Python

Functions in the lib library include a copy function that you can access in this way:

from Lib import copy

All the copy functions are static: No classes are involved. The two methods of interest are

newarray = copy.copy(array)

and

Click here to view code image

newarray = copy.deepcopy(array)

The first function makes a shallow copy of the array of objects. The second makes a deep copy, ensuring that all objects are copied and that any references stay separate from the original array of objects.

If you are copying simple lists or arrays of objects, the first function works fine. It is only if the objects contain references to other objects that you need to invoke the complexity and slower execution time of the deep copy.

Using the Prototype

Now let’s write a simple program that reads data from a database and then clones the resulting object. In the example program, Proto, these data were merely read from a file, but the original data were derived from a large database (as we just discussed).

Then we create a class called Swimmer that holds one name, club name, sex, and time, just as we did earlier. We also create a class called Swimmers that maintains a list of the Swimmers we read in from the database.

In addition, we provide a getSwimmer method in the SwimData class and getName methods in the Swimmer class for accessing the age, sex, and times. After we’ve read the data into SwimInfo, we can display it in a listbox.

Then when the user clicks the Clone button, we’ll clone this class and sort the data differently in the new class. Again, we clone the data because

creating a new class instance would be much slower, and we want to keep the data in both forms.

In the original class, the names are sorted by sex and then by time. In the cloned class, they are sorted only by time. In Figure 10-1, you can see the simple user interface that enables you to display the original data on the left and the sorted data in the cloned class on the right.

Figure 10-1 Original data on the left, sorted data on the right

The listbox on the left is loaded when the program starts and the listbox on the right is loaded when you click the Copy button. Now click the Refresh button to refresh the leftmost listbox from the original data array (see Figure 10-2).

Figure 10-2 Original data on the left were also sorted because a shallow copy was used

Why were the names in the leftmost listbox also re-sorted? This occurs because we used a real shallow copy, just copying the original array into a new one.

Click here to view code image

def shallowCopy(self):

swmrs = self.swmrs # copies the pointers sw = self.sbySex(swmrs)

self.fillList(self.rightlist, sw)

In other words, the references to the data objects are copies, but they refer to the same underlying data. Thus, any operation performed on the copied data also occurs on the original data in the Prototype class. This isn’t what we want here.

Instead, you should click the Clone button, which calls the copy.copy

function we described above, and you have a separate list of swimmers than can be sorted without affecting the original.

Click here to view code image

def clone(self):

swmrs = copy.copy(self.swmrs)

sw = self.sbySex(swmrs)

self.fillList(self.rightlist, sw)

This gives you the display you want, and it is unchanged even after you click Refresh (see Figure 10-3).

Figure 10-3 Clone and Copy make two separate arrays, with the left unchanged

We include the Reload button, which rereads the original swimmer file.

Consequences of the Prototype Pattern

Using the Prototype pattern, you can add and remove classes at runtime by cloning them as needed. You can revise the internal data representation of a class at runtime based on program conditions. You can also specify new objects at runtime without creating a proliferation of classes and inheritance structures.

As with the registry of Singletons discussed in in Chapter 8, “The Singleton Pattern,” you can also create a registry of Prototype classes that can be cloned and ask the registry object for a list of possible prototypes. You may be able to clone an existing class instead of writing one from scratch.

Note that every class that you might use as a prototype must itself be instantiated (perhaps at some expense) for you to use a Prototype registry. This can be a performance drawback.

Finally, the idea of having prototype classes to copy implies that you have sufficient access to the data or methods in these classes to change them after cloning. This may require adding data access methods to these prototype classes so that you can modify the data after you have cloned the class.

Sample Code on GitHub

In all these samples, be sure to include the data file (swimmers.txt) in the same folder as the Python file. Also make sure they are part of the project in Vscode or PyCharm.

  • Proto.py: Creates the Swimmers prototype demo in this chapter
    • Swimmers.txt: Data file for Proto

'James Cooper - Python Programming with D' 카테고리의 다른 글

The Adapter Pattern  (0) 2023.03.23
Summary of Creational Patterns  (0) 2023.03.23
The Prototype Pattern  (0) 2023.03.23
The Singleton Pattern  (0) 2023.03.23
The Abstract Factory Pattern  (0) 2023.03.23

댓글