该示例是一个影片出租店用的程序。书中设计了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())