问题场景

小王是某游戏公司的新入职的职员,有一天,组长交给了他一个任务,为一个即将准开发的一款游戏设计一些人物角色,其中包括多种职业,如牧师、战士和法师等等。每种职业都有一些自身独有的属性和技能,但是也会有一些共有的属性和方法。假设这家公司是用 Python 来开发游戏的。

经历过面向对象编程学习的小王很快就理清了思路,这需要用类的思想来进行设计。由于这些职业都会有一些共有的属性和方法,显然应该把这些职业的共有属性和方法拿出来作为一个公共的类,而这个公共的类就叫做基类,或者称为父类;其它职业可以基于这个公共的类来进行增加属性和方法,这些职业的类就叫做子类。这就是面向对象编码中的继承的思想,理清了设计思路之后,小王立马开始动手来实现相应的代码。


父类设计

首先,对于每一个游戏角色,它都会有姓名和性别属性。组长又告诉小王,我们不能让其它人知道我们的角色是怎么设计的,以及都有哪些属性,这又该如何设计呢?聪明的小王立马就想到了封装的思想,通过隐藏对象的属性和实现细节可以防止外部的类直接调用属性或者修改属性。所以小王立马写出了如下的代码:

class Roler(object):
    """
    用户角色类,需要隐藏属性
    Args:
        __username: 用户名,string
        __sex:性别, string
    """
    def __init__(self, name=None, sex="male"):
        self.__username = name
        self.__sex = sex
        self.__hp = 1000

    def get_username(self):
        # 获取用户名
        return self.__username

    def get_sex(self):
        # 获取用户性别
        return self.__sex

    def add_hp(self, hpr):
        # 角色可以回血
        self.__hp += hpr

    def __repr__(self):
        # 打印对象信息
        return "username : {0}\nsex : {1}\nhp : {2}".format(self.__username, self.__sex, self.__hp)

不同于 JavaC++ ,在 Python 中是没有 private 等关键字的。所以我们如何来定义一个类的属性是私有的呢?方法就是在类属性的名字前加上两个下划线,即表示成 __username 的形式,这就是私有属性的定义方式了。其原因是因为 Python 的类的内部,所有双下划线的开始的名字都会被替换成增加单下划线和类名的方式。实质上,__username 就被替换成了 _Roler__username 的形式了。

role1 = Roler("weisheng", "male") # 建立一个新角色
print(role1) # 打印该角色的信息,调用 __repr__() 方法

print(role1.__username) # AttributeError,该属性是私有的
print(role1._Roler__username) # weisheng,可以打印

子类设计

有了父类还不够,由于每个职业都会有一些自身特有的属性和方法。所以,对于每个职业,我们也需要实现一个类。小王首先针对牧师这个职业来实现,牧师作为一个法系医疗职业,首先肯定需要一个 MP 值。同时,它能给其它用户恢复生命值。因此,可以按照如下方式来实现牧师类:

class Pastor(Roler):
    """
    牧师类,继承自用户角色类
    Args:
        __MP: 魔法值
    """
    def __init__(self, name, sex):
        # 调用父类的构造函数
        super().__init__(name, sex)
        self.__mp = 100
    def get_mp(self):
        return self.__mp
    def __repr__(self):
        return super().__repr__() + "\nmp : {0}".format(self.__mp)

    def fullhealth(self, other):
        # 技能1:回复其它用户生命值
        other.add_hp(200)

在定义的牧师类中,首先调用父类的构造函数来对用户姓名、性别、hp值进行初始化。同时,牧师还有个mp值,这个属性是该职业独有的(请勿追究细节)。由于增加了相应的属性,所以 __repr__() 方法也需要重写,可以通过调用父类的 __repr__() 方法再加上牧师类独有的属性。

牧师还有一个技能,他能给其它的用户角色回血,所以需要实习一个 fullhealth() 方法,参数是其它的角色类。测试用例如下:

pastor1 = Pastor("ergouzi", "male") # 建立一个牧师职业
print(pastor1)  # 打印该职业角色的信息

pastor1.fullhealth(role1)  # 牧师可以给其他角色回血
print(role1)  # 可以发现该用户的 hp 值发生变化

其他职业的设计可以参照该职业的特点来做出相应的设计,这里就不在多做说明了。


面向对象总结

通过跟随小王的游戏角色设计,相信你已经对 Python 中的面向对象编程有了一定的了解了。面向对象编程是现在常用的一种编程方式,它是相对于面向过程编程来说的。面向对象编程把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。该思想最主要的三个特点就是封装、继承和多态,其实这些特点在上述的实例中都有体现,你能发现吗?

虽然上述的例子已经阐述了面向对象编程的大部分思想,但是本人也是第一次去进行这些类间关系的设计,所以每个例子都是非常简单的,可能在思想设计上也存在问题,请见谅。

全部代码请访问:面向对象编程

更多精彩内容将发布在公众号 冰咖啡与狗 ,或搜索微信号 icedcoffee7 添加公众号。

Python面向对象知多少?-LMLPHP

06-07 17:47