面向对象相关知识
三大支柱:封装、继承、多态
例子:工资结算系统。
"""
月薪结算系统 - 部门经理每月15000 程序员每小时200 销售员1800底薪加销售额5%提成
"""
from abc import ABCMeta, abstractmethod
class Employee(metaclass=ABCMeta):
"""员工(抽象类)"""
def __init__(self, name):
self.name = name
@abstractmethod
def get_salary(self):
"""结算月薪(抽象方法)"""
pass
class Manager(Employee):
"""部门经理"""
def get_salary(self):
return 15000.0
class Programmer(Employee):
"""程序员"""
def __init__(self, name, working_hour=0):
self.working_hour = working_hour
super().__init__(name)
def get_salary(self):
return 200.0 * self.working_hour
class Salesman(Employee):
"""销售员"""
def __init__(self, name, sales=0.0):
self.sales = sales
super().__init__(name)
def get_salary(self):
return 1800.0 + self.sales * 0.05
class EmployeeFactory:
"""创建员工的工厂(工厂模式 - 通过工厂实现对象使用者和对象之间的解耦合)"""
@staticmethod
def create(emp_type, *args, **kwargs):
"""创建员工"""
all_emp_types = {'M': Manager, 'P': Programmer, 'S': Salesman}
cls = all_emp_types[emp_type.upper()]
return cls(*args, **kwargs) if cls else None
def main():
"""主函数"""
emps = [
EmployeeFactory.create('M', '曹操'),
EmployeeFactory.create('P', '荀彧', 120),
EmployeeFactory.create('P', '郭嘉', 85),
EmployeeFactory.create('S', '典韦', 123000),
]
for emp in emps:
print(f'{emp.name}: {emp.get_salary():.2f}元')
if __name__ == '__main__':
main()
@staticmethod
:定义不依赖于类实例或类状态的静态方法。@abstractmethod
:定义抽象基类中的抽象方法,要求子类实现这些方法。
通过工厂模式,客户端代码无需知道具体的类名和构造函数细节,只需提供所需对象的类型,工厂类会负责创建并返回相应的对象。
单一职责原则:
对象创建的逻辑集中在工厂类中,客户端代码只负责使用对象。这符合单一职责原则(Single Responsibility Principle),使代码结构更加清晰。不使用工厂模式的话客户端代码既负责创建对象又负责使用对象,职责不单一,增加了代码的复杂性。
例子:扑克游戏。
"""
经验:符号常量总是优于字面常量,枚举类型是定义符号常量的最佳选择
"""
from enum import Enum, unique
import random
@unique
class Suite(Enum):
"""花色"""
SPADE, HEART, CLUB, DIAMOND = range(4)
def __lt__(self, other):
return self.value < other.value
class Card:
"""牌"""
def __init__(self, suite, face):
"""初始化方法"""
self.suite = suite
self.face = face
def show(self):
"""显示牌面"""
suites = ['♠︎', '♥︎', '♣︎', '♦︎']
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
return f'{suites[self.suite.value]}{faces[self.face]}'
def __repr__(self):
return self.show()
class Poker:
"""扑克"""
def __init__(self):
self.index = 0
self.cards = [Card(suite, face)
for suite in Suite
for face in range(1, 14)]
def shuffle(self):
"""洗牌(随机乱序)"""
random.shuffle(self.cards)
self.index = 0
def deal(self):
"""发牌"""
card = self.cards[self.index]
self.index += 1
return card
@property
def has_more(self):
return self.index < len(self.cards)
class Player:
"""玩家"""
def __init__(self, name):
self.name = name
self.cards = []
def get_one(self, card):
"""摸一张牌"""
self.cards.append(card)
def sort(self, comp=lambda card: (card.suite, card.face)):
"""整理手上的牌"""
self.cards.sort(key=comp)
def main():
"""主函数"""
poker = Poker()
poker.shuffle()
players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]
while poker.has_more:
for player in players:
player.get_one(poker.deal())
for player in players:
player.sort()
print(player.name, end=': ')
print(player.cards)
if __name__ == '__main__':
main()
继承 Enum
表示定义一个枚举类。枚举(Enumeration)是一个包含一组名称和值对的集合,每个成员都是唯一的常量。通过继承 Enum
类,我们可以创建一组有意义的常量,通常用于表示一组相关的常量值,如一副牌中的花色或一周中的天数。
@unique
是一个装饰器,用于确保枚举类中的值是唯一的。如果枚举类中存在重复的值,@unique
会抛出 ValueError
异常。这对于防止枚举类中的成员具有相同的值非常有用。
__lt__
方法是 Python 的特殊方法之一,用于实现小于比较运算符 <
。在枚举类中定义 __lt__
方法,可以自定义两个枚举成员之间的比较规则。
在 Python 中,特殊方法(或魔术方法)是以双下划线开头和结尾的方法,用于实现特定的操作行为。__lt__
方法是其中之一,用于实现小于比较运算符 <
。当你在对象上使用 <
运算符时,Python 会调用该对象的 __lt__
方法。
key=comp
指定了排序的键函数。在这里,comp
是一个匿名函数 lambda card: (card.suite, card.face)
,它将每张牌转换为一个包含 suite
和 face
的元组。Python 将使用这些元组进行排序。