重构 改善既有代码的设计 第1章 Python版

该示例是一个影片出租店用的程序。书中设计了3个类,分别为:Movie、Rental、Customer。

1、基本程序

1.1、Movie类

Movie类包括:

  • 3个公共成员变量:CHILDRENS、REGULAR、NEW_RELEASE。大写表示仅可引用,不可复制。
  • 2个私有成员变量:__title、__price_code。前缀两个下划线“__”表示私有。
  • 构造函数:__init()。可以在类的外部通过 类名(值1, 值2) 这种形式对对象绑定值。
  • 三个公共成员函数:get_price_code()、get_price_code()、set_price_code()。可以在类的外部访问他们。
 1 # 定义类 Movie
 2 class Movie:
 3     CHILDRENS = 2
 4     REGULAR = 0
 5     NEW_RELEASE = 1
 6     # 私有成员
 7     __title = ''
 8     __price_code = 0
 9 
10     # 定义构造函数
11     def __init__(self, title, price_code):
12         self.__title = title
13         self.__price_code = price_code
14 
15     def get_price_code(self):
16         return self.__price_code
17 
18     def set_price_code(self, arg):
19         self.__price_code = arg
20 
21     def get_title(self):
22         return self.__title

1.2、Rental类

Rental类包括:

  • 两个私有成员变量:__days_rented、__movie。其中 __movie 在构造函数中定义。
  • 构造函数:__init__()。
  • 两个公共成员函数:get_days_rented()、get_movie()。
 1 # 定义类 Rental
 2 class Rental():
 3     # 该类有两个成员变量: __moive 和 __days_rented
 4     __days_rented = 0
 5 
 6     # 定义 构造函数
 7     def __init__(self, movie, days_rented):
 8         self.__moive = movie
 9         self.__days_rented = days_rented
10 
11     def get_days_rented(self):
12         return self.__days_rented
13 
14     def get_moive(self):
15         return self.__moive

1.3、Customer类

Customer类包括:

  • 两个私有成员变量:__name、__rentals。
  • 构造函数:__init__()。
  • 两个公共成员函数:get_name()、statement()。其中,statement()完成了主要的逻辑计算任务。
 1 # 定义类 Customer
 2 class Customer():
 3     __name = ''
 4     __rentals = []
 5 
 6     # 定义构造函数
 7     def __init__(self, name):
 8         self.__name = name
 9 
10     def add_rental(self, arg):
11         self.__rentals.append(arg)
12 
13     def get_name(self):
14         return self.__name
15 
16     def statement(self):
17         total_amount = 0
18         frequent_renter_points = 0
19         result = 'Rental Record for ' + self.get_name() + '\n'
20         for each_rental in self.__rentals:
21             this_amount = 0
22             # determin amounts for each line
23             if each_rental.get_moive().get_price_code() == Movie.REGULAR:
24                 this_amount += 2
25                 if each_rental.get_days_rented() > 2:
26                     this_amount += (each_rental.get_days_rented() - 2) * 1.5
27                     # 该指令会中断 for 循环,因此注释掉
28                     # break
29             else:
30                 if each_rental.get_moive().get_price_code() == Movie.NEW_RELEASE:
31                     this_amount += each_rental.get_days_rented() * 3
32                     # 该指令会中断 for 循环,因此注释掉
33                     # break
34                 else:
35                     if each_rental.get_moive().get_price_code() == Movie.CHILDRENS:
36                         this_amount += 1.5
37                         if each_rental.get_days_rented() > 3:
38                             this_amount += (each_rental.get_days_rented() - 3) * 1.5
39 
40             # add frequent renter points
41             frequent_renter_points += 1
42             # add bonus for a two day new release rental
43             if each_rental.get_moive().get_price_code() == Movie.NEW_RELEASE and each_rental.get_days_rented() > 1:
44                 frequent_renter_points += 1
45 
46             # show figures for this rental
47             result += '\t' + each_rental.get_moive().get_title() + '\t' + str(this_amount) + '\n'
48             total_amount += this_amount
49         # add footer lines
50         result += 'Amount owed is ' + str(total_amount) + '\n'
51         result += 'You earned ' + str(frequent_renter_points) + ' frequent renter points'
52         return result
扫描二维码关注公众号,回复: 5072796 查看本文章

1.4、调用类输出结果

为了验证以上三个类是否正确,编写以下程序验证。行3、5、7、8是为了给customer的成员变量绑定值。行9进行计算并打印结果。

1 # 电影名为 Allan
2 # 票价为 1
3 movie_rented = Movie('Allan', 1)
4 # 电影租赁天数: 10
5 movie_rental = Rental(movie_rented, 10)
6 # 租借人: Mc
7 customer = Customer('Mc')
8 customer.add_rental(movie_rental)
9 print(customer.statement())

1.5、完整程序

完整的示例程序如下:

  1 # -*- coding: utf-8 -*-
  2 
  3 
  4 # 定义类 Movie
  5 class Movie:
  6     CHILDRENS = 2
  7     REGULAR = 0
  8     NEW_RELEASE = 1
  9     # 私有成员
 10     __title = ''
 11     __price_code = 0
 12 
 13     # 定义构造函数
 14     def __init__(self, title, price_code):
 15         self.__title = title
 16         self.__price_code = price_code
 17 
 18     def get_price_code(self):
 19         return self.__price_code
 20 
 21     def set_price_code(self, arg):
 22         self.__price_code = arg
 23 
 24     def get_title(self):
 25         return self.__title
 26 
 27 
 28 # 定义类 Rental
 29 class Rental():
 30     # 该类有两个成员变量: __moive 和 __days_rented
 31     __days_rented = 0
 32 
 33     # 定义 构造函数
 34     def __init__(self, movie, days_rented):
 35         self.__moive = movie
 36         self.__days_rented = days_rented
 37 
 38     def get_days_rented(self):
 39         return self.__days_rented
 40 
 41     def get_moive(self):
 42         return self.__moive
 43 
 44 
 45 # 定义类 Customer
 46 class Customer():
 47     __name = ''
 48     __rentals = []
 49 
 50     # 定义构造函数
 51     def __init__(self, name):
 52         self.__name = name
 53 
 54     def add_rental(self, arg):
 55         self.__rentals.append(arg)
 56 
 57     def get_name(self):
 58         return self.__name
 59 
 60     def statement(self):
 61         total_amount = 0
 62         frequent_renter_points = 0
 63         result = 'Rental Record for ' + self.get_name() + '\n'
 64         for each_rental in self.__rentals:
 65             this_amount = 0
 66             # determin amounts for each line
 67             if each_rental.get_moive().get_price_code() == Movie.REGULAR:
 68                 this_amount += 2
 69                 if each_rental.get_days_rented() > 2:
 70                     this_amount += (each_rental.get_days_rented() - 2) * 1.5
 71                     # 该指令会中断 for 循环,因此注释掉
 72                     # break
 73             else:
 74                 if each_rental.get_moive().get_price_code() == Movie.NEW_RELEASE:
 75                     this_amount += each_rental.get_days_rented() * 3
 76                     # 该指令会中断 for 循环,因此注释掉
 77                     # break
 78                 else:
 79                     if each_rental.get_moive().get_price_code() == Movie.CHILDRENS:
 80                         this_amount += 1.5
 81                         if each_rental.get_days_rented() > 3:
 82                             this_amount += (each_rental.get_days_rented() - 3) * 1.5
 83 
 84             # add frequent renter points
 85             frequent_renter_points += 1
 86             # add bonus for a two day new release rental
 87             if each_rental.get_moive().get_price_code() == Movie.NEW_RELEASE and each_rental.get_days_rented() > 1:
 88                 frequent_renter_points += 1
 89 
 90             # show figures for this rental
 91             result += '\t' + each_rental.get_moive().get_title() + '\t' + str(this_amount) + '\n'
 92             total_amount += this_amount
 93         # add footer lines
 94         result += 'Amount owed is ' + str(total_amount) + '\n'
 95         result += 'You earned ' + str(frequent_renter_points) + ' frequent renter points'
 96         return result
 97 
 98 
 99 # 电影名为 Allan
100 # 票价为 1
101 movie_rented = Movie('Allan', 1)
102 # 电影租赁天数: 10
103 movie_rental = Rental(movie_rented, 10)
104 # 租借人: Mc
105 customer = Customer('Mc')
106 customer.add_rental(movie_rental)
107 print(customer.statement())

 2、重构判断语句

2.1、重构依据

  • 找出函数内的局部变量和参数
  • 不被修改的变量作为函数的参数
  • 被修改的变量仅有一个时,作为函数的返回值

2.2、重构amount_for()方法

 1 def amount_for(self, rental):
 2         this_amount = 0
 3         if rental.get_moive().get_price_code() == Movie.REGULAR:
 4             this_amount += 2
 5             if rental.get_days_rented() > 2:
 6                 this_amount += (rental.get_days_rented() - 2) * 1.5
 7                 # 该指令会中断 for 循环,因此注释掉
 8                 # break
 9         else:
10             if rental.get_moive().get_price_code() == Movie.NEW_RELEASE:
11                 this_amount += rental.get_days_rented() * 3
12                 # 该指令会中断 for 循环,因此注释掉
13                 # break
14             else:
15                 if rental.get_moive().get_price_code() == Movie.CHILDRENS:
16                     this_amount += 1.5
17                     if rental.get_days_rented() > 3:
18                         this_amount += (rental.get_days_rented() - 3) * 1.5
19         return this_amount

2.3、完整程序

  1 # -*- coding: utf-8 -*-
  2 
  3 
  4 # 定义类 Movie
  5 class Movie:
  6     CHILDRENS = 2
  7     REGULAR = 0
  8     NEW_RELEASE = 1
  9     # 私有成员
 10     __title = ''
 11     __price_code = 0
 12 
 13     # 定义构造函数
 14     def __init__(self, title, price_code):
 15         self.__title = title
 16         self.__price_code = price_code
 17 
 18     def get_price_code(self):
 19         return self.__price_code
 20 
 21     def set_price_code(self, arg):
 22         self.__price_code = arg
 23 
 24     def get_title(self):
 25         return self.__title
 26 
 27 
 28 # 定义类 Rental
 29 class Rental():
 30     # 该类有两个成员变量: __moive 和 __days_rented
 31     __days_rented = 0
 32 
 33     # 定义 构造函数
 34     def __init__(self, movie, days_rented):
 35         self.__moive = movie
 36         self.__days_rented = days_rented
 37 
 38     def get_days_rented(self):
 39         return self.__days_rented
 40 
 41     def get_moive(self):
 42         return self.__moive
 43 
 44 
 45 # 定义类 Customer
 46 class Customer():
 47     __name = ''
 48     __rentals = []
 49 
 50     # 定义构造函数
 51     def __init__(self, name):
 52         self.__name = name
 53 
 54     def add_rental(self, arg):
 55         self.__rentals.append(arg)
 56 
 57     def get_name(self):
 58         return self.__name
 59 
 60     def amount_for(self, rental):
 61         this_amount = 0
 62         if rental.get_moive().get_price_code() == Movie.REGULAR:
 63             this_amount += 2
 64             if rental.get_days_rented() > 2:
 65                 this_amount += (rental.get_days_rented() - 2) * 1.5
 66                 # 该指令会中断 for 循环,因此注释掉
 67                 # break
 68         else:
 69             if rental.get_moive().get_price_code() == Movie.NEW_RELEASE:
 70                 this_amount += rental.get_days_rented() * 3
 71                 # 该指令会中断 for 循环,因此注释掉
 72                 # break
 73             else:
 74                 if rental.get_moive().get_price_code() == Movie.CHILDRENS:
 75                     this_amount += 1.5
 76                     if rental.get_days_rented() > 3:
 77                         this_amount += (rental.get_days_rented() - 3) * 1.5
 78         return this_amount
 79 
 80     def statement(self):
 81         total_amount = 0
 82         frequent_renter_points = 0
 83         result = 'Rental Record for ' + self.get_name() + '\n'
 84         for each_rental in self.__rentals:
 85             # determin amounts for each line
 86             this_amount = self.amount_for(each_rental)
 87 
 88             # add frequent renter points
 89             frequent_renter_points += 1
 90             # add bonus for a two day new release rental
 91             if each_rental.get_moive().get_price_code() == Movie.NEW_RELEASE and each_rental.get_days_rented() > 1:
 92                 frequent_renter_points += 1
 93 
 94             # show figures for this rental
 95             result += '\t' + each_rental.get_moive().get_title() + '\t' + str(this_amount) + '\n'
 96             total_amount += this_amount
 97         # add footer lines
 98         result += 'Amount owed is ' + str(total_amount) + '\n'
 99         result += 'You earned ' + str(frequent_renter_points) + ' frequent renter points'
100         return result
101 
102 
103 # 电影名为 Allan
104 # 票价为 1
105 movie_rented = Movie('Allan', 1)
106 # 电影租赁天数: 10
107 movie_rental = Rental(movie_rented, 10)
108 # 租借人: Mc
109 customer = Customer('Mc')
110 customer.add_rental(movie_rental)
111 print(customer.statement())

3、重构函数内的变量更名

改名可以提高代码的清晰度。

3.1、更名后的amount_for函数

将 rental 改为 a_rental,将 this_amount 改为result。

 1 def amount_for(self, a_rental):
 2         result = 0
 3         if a_rental.get_moive().get_price_code() == Movie.REGULAR:
 4             result += 2
 5             if a_rental.get_days_rented() > 2:
 6                 result += (a_rental.get_days_rented() - 2) * 1.5
 7                 # 该指令会中断 for 循环,因此注释掉
 8                 # break
 9         else:
10             if a_rental.get_moive().get_price_code() == Movie.NEW_RELEASE:
11                 result += a_rental.get_days_rented() * 3
12                 # 该指令会中断 for 循环,因此注释掉
13                 # break
14             else:
15                 if a_rental.get_moive().get_price_code() == Movie.CHILDRENS:
16                     result += 1.5
17                     if a_rental.get_days_rented() > 3:
18                         result += (a_rental.get_days_rented() - 3) * 1.5
19         return result

3.2、完整程序

  1 # -*- coding: utf-8 -*-
  2 
  3 
  4 # 定义类 Movie
  5 class Movie:
  6     CHILDRENS = 2
  7     REGULAR = 0
  8     NEW_RELEASE = 1
  9     # 私有成员
 10     __title = ''
 11     __price_code = 0
 12 
 13     # 定义构造函数
 14     def __init__(self, title, price_code):
 15         self.__title = title
 16         self.__price_code = price_code
 17 
 18     def get_price_code(self):
 19         return self.__price_code
 20 
 21     def set_price_code(self, arg):
 22         self.__price_code = arg
 23 
 24     def get_title(self):
 25         return self.__title
 26 
 27 
 28 # 定义类 Rental
 29 class Rental():
 30     # 该类有两个成员变量: __moive 和 __days_rented
 31     __days_rented = 0
 32 
 33     # 定义 构造函数
 34     def __init__(self, movie, days_rented):
 35         self.__moive = movie
 36         self.__days_rented = days_rented
 37 
 38     def get_days_rented(self):
 39         return self.__days_rented
 40 
 41     def get_moive(self):
 42         return self.__moive
 43 
 44 
 45 # 定义类 Customer
 46 class Customer():
 47     __name = ''
 48     __rentals = []
 49 
 50     # 定义构造函数
 51     def __init__(self, name):
 52         self.__name = name
 53 
 54     def add_rental(self, arg):
 55         self.__rentals.append(arg)
 56 
 57     def get_name(self):
 58         return self.__name
 59 
 60     def amount_for(self, a_rental):
 61         result = 0
 62         if a_rental.get_moive().get_price_code() == Movie.REGULAR:
 63             result += 2
 64             if a_rental.get_days_rented() > 2:
 65                 result += (a_rental.get_days_rented() - 2) * 1.5
 66                 # 该指令会中断 for 循环,因此注释掉
 67                 # break
 68         else:
 69             if a_rental.get_moive().get_price_code() == Movie.NEW_RELEASE:
 70                 result += a_rental.get_days_rented() * 3
 71                 # 该指令会中断 for 循环,因此注释掉
 72                 # break
 73             else:
 74                 if a_rental.get_moive().get_price_code() == Movie.CHILDRENS:
 75                     result += 1.5
 76                     if a_rental.get_days_rented() > 3:
 77                         result += (a_rental.get_days_rented() - 3) * 1.5
 78         return result
 79 
 80     def statement(self):
 81         total_amount = 0
 82         frequent_renter_points = 0
 83         result = 'Rental Record for ' + self.get_name() + '\n'
 84         for each_rental in self.__rentals:
 85             # determin amounts for each line
 86             this_amount = self.amount_for(each_rental)
 87 
 88             # add frequent renter points
 89             frequent_renter_points += 1
 90             # add bonus for a two day new release rental
 91             if each_rental.get_moive().get_price_code() == Movie.NEW_RELEASE and each_rental.get_days_rented() > 1:
 92                 frequent_renter_points += 1
 93 
 94             # show figures for this rental
 95             result += '\t' + each_rental.get_moive().get_title() + '\t' + str(this_amount) + '\n'
 96             total_amount += this_amount
 97         # add footer lines
 98         result += 'Amount owed is ' + str(total_amount) + '\n'
 99         result += 'You earned ' + str(frequent_renter_points) + ' frequent renter points'
100         return result
101 
102 
103 # 电影名为 Allan
104 # 票价为 1
105 movie_rented = Movie('Allan', 1)
106 # 电影租赁天数: 10
107 movie_rental = Rental(movie_rented, 10)
108 # 租借人: Mc
109 customer = Customer('Mc')
110 customer.add_rental(movie_rental)
111 print(customer.statement())

 4、搬移“金额计算”代码

4.1、“金额计算”代码的问题

“金额计算”函数 amount_for() 使用了来自 Rental 类的信息,却没有使用来自 Customer 类的信息。因此将它移入 Rental 类,并改名“get_charge()”。

4.2、完整程序

  1 # -*- coding: utf-8 -*-
  2 
  3 
  4 # 定义类 Movie
  5 class Movie:
  6     CHILDRENS = 2
  7     REGULAR = 0
  8     NEW_RELEASE = 1
  9     # 私有成员
 10     __title = ''
 11     __price_code = 0
 12 
 13     # 定义构造函数
 14     def __init__(self, title, price_code):
 15         self.__title = title
 16         self.__price_code = price_code
 17 
 18     def get_price_code(self):
 19         return self.__price_code
 20 
 21     def set_price_code(self, arg):
 22         self.__price_code = arg
 23 
 24     def get_title(self):
 25         return self.__title
 26 
 27 
 28 # 定义类 Rental
 29 class Rental():
 30     # 该类有两个成员变量: __moive 和 __days_rented
 31     __days_rented = 0
 32 
 33     # 定义 构造函数
 34     def __init__(self, movie, days_rented):
 35         self.__moive = movie
 36         self.__days_rented = days_rented
 37 
 38     def get_days_rented(self):
 39         return self.__days_rented
 40 
 41     def get_moive(self):
 42         return self.__moive
 43 
 44     def get_charge(self):
 45         result = 0
 46         if self.get_moive().get_price_code() == Movie.REGULAR:
 47             result += 2
 48             if self.get_days_rented() > 2:
 49                 result += (self.get_days_rented() - 2) * 1.5
 50                 # 该指令会中断 for 循环,因此注释掉
 51                 # break
 52         else:
 53             if self.get_moive().get_price_code() == Movie.NEW_RELEASE:
 54                 result += self.get_days_rented() * 3
 55                 # 该指令会中断 for 循环,因此注释掉
 56                 # break
 57             else:
 58                 if self.get_moive().get_price_code() == Movie.CHILDRENS:
 59                     result += 1.5
 60                     if self.get_days_rented() > 3:
 61                         result += (self.get_days_rented() - 3) * 1.5
 62         return result
 63 
 64 
 65 # 定义类 Customer
 66 class Customer():
 67     __name = ''
 68     __rentals = []
 69 
 70     # 定义构造函数
 71     def __init__(self, name):
 72         self.__name = name
 73 
 74     def add_rental(self, arg):
 75         self.__rentals.append(arg)
 76 
 77     def get_name(self):
 78         return self.__name
 79 
 80     def statement(self):
 81         total_amount = 0
 82         frequent_renter_points = 0
 83         result = 'Rental Record for ' + self.get_name() + '\n'
 84         for each_rental in self.__rentals:
 85             # determin amounts for each line
 86             this_amount = each_rental.get_charge()
 87 
 88             # add frequent renter points
 89             frequent_renter_points += 1
 90             # add bonus for a two day new release rental
 91             if each_rental.get_moive().get_price_code() == Movie.NEW_RELEASE and each_rental.get_days_rented() > 1:
 92                 frequent_renter_points += 1
 93 
 94             # show figures for this rental
 95             result += '\t' + each_rental.get_moive().get_title() + '\t' + str(this_amount) + '\n'
 96             total_amount += this_amount
 97         # add footer lines
 98         result += 'Amount owed is ' + str(total_amount) + '\n'
 99         result += 'You earned ' + str(frequent_renter_points) + ' frequent renter points'
100         return result
101 
102 
103 # 电影名为 Allan
104 # 票价为 1
105 movie_rented = Movie('Allan', 1)
106 # 电影租赁天数: 10
107 movie_rental = Rental(movie_rented, 10)
108 # 租借人: Mc
109 customer = Customer('Mc')
110 customer.add_rental(movie_rental)
111 print(customer.statement())

猜你喜欢

转载自www.cnblogs.com/mcgill0217/p/10322400.html
今日推荐