[
127
]
For the previous code, maybe yes, maybe no. With our recent experience in
object-oriented principles, we can write an object-oriented version in record
time. Let's compare them
import math
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, p2):
return math.sqrt((self.x-p2.x)**2 + (self.y-p2.y)**2)
class Polygon:
def __init__(self):
self.vertices = []
def add_point(self, point):
self.vertices.append((point))
def perimeter(self):
perimeter = 0
points = self.vertices + [self.vertices[0]]
for i in range(len(self.vertices)):
perimeter += points[i].distance(points[i+1])
return perimeter
As we can see from the highlighted sections, there is twice as much code here
as there was in our earlier version, although we could argue that the
add_point
method is not strictly necessary.
Now, to understand the differences a little better, let's compare the two APIs in use.
Here's how to calculate the perimeter of a square using the object-oriented code:
>>> square = Polygon()
>>> square.add_point(Point(1,1))
>>> square.add_point(Point(1,2))
>>> square.add_point(Point(2,2))
>>> square.add_point(Point(2,1))
>>> square.perimeter()
4.0
www.it-ebooks.info
When to Use Object-oriented Programming
[
128
]
That's fairly succinct and easy to read, you might think, but let's compare it to the
function-based code:
>>> square = [(1,1), (1,2), (2,2), (2,1)]
>>> perimeter(square)
4.0
Hmm, maybe
the object-oriented API isn't so compact! That said, I'd argue that it
was easier to
read
than the functional example: How do we know what the list of
tuples is supposed to represent in the second version? How do we remember what
kind of object (a list of two-tuples? That's not intuitive!) we're supposed to pass into
the
perimeter
function? We would need a lot of documentation to explain how
these functions should be used.
In contrast, the object-oriented code is relatively self-documenting, we just have to
look at the list of methods and their parameters to know what the object does and
how to use it. By the time we wrote all the documentation for the functional version,
it would probably be longer than the object-oriented code.
Finally, code length is not a good indicator of code complexity. Some programmers
get hung up on complicated "one liners" that do an incredible amount of work in one
line of code. This can be a fun exercise, but the result is often unreadable, even to the
original author the following day. Minimizing the amount of code can often make a
program easier to read, but do not blindly assume this is the case.
Luckily, this trade-off isn't necessary. We can make the object-oriented
Polygon
API as easy to use as the functional implementation. All we have to do is alter our
Polygon
class so that it can be constructed with multiple points. Let's give it an
initializer that accepts a list of
Point
objects. In fact, let's allow it to accept tuples
too, and we can construct the
Point
objects ourselves, if needed:
def __init__(self, points=None):
points = points if points else []
self.vertices = []
for point in points:
if isinstance(point, tuple):
point = Point(*point)
self.vertices.append(point)
This initializer goes through the list and ensures that any tuples are converted to
points. If the object is not a tuple, we leave it as is, assuming that it is either a
Point
object already, or an unknown duck-typed object that can act like a
Point
object.
www.it-ebooks.info
Chapter 5
Do'stlaringiz bilan baham: |