一、初识面向对象:从现实世界到代码世界

大家好,我是你们这门课的老朋友。今天咱们聊聊面向对象编程——说白了,就是怎么用代码去模拟我们看到的这个世界。

我记得刚入行那会儿,写代码全是函数堆出来的。一个项目下来,几千行的函数满天飞,改一个地方,崩三个地方。后来带我的老大哥说:「你试试用面向对象的方式去思考。」这一试,就再也没回头。

1.1 现实世界 vs 代码世界

你想想看,现实世界里有什么?有「人」、「车」、「房子」这些类别,也有「张三」、「我的特斯拉」、「那栋写字楼」这些具体的个体。

代码世界也一样。我们管类别叫类(Class),管具体的个体叫对象(Object)

核心对应关系:

  • = 现实世界中的「类别」——比如「狗」这个物种
  • 对象 = 现实世界中的「具体个体」——比如你家那只叫旺财的柴犬
  • 属性 = 对象的特征——比如旺财的毛色是黄的,体重15公斤
  • 方法 = 对象的行为——比如旺财会叫、会跑、会摇尾巴

嗯,这里要注意:类是一张蓝图,对象才是真正住进内存的那个实体。我在项目中遇到过不少新手,把类当对象用,结果数据全串了——那叫一个惨。

1.2 第一个类:用代码描述一只狗

光说不练假把式。咱们直接上代码。我习惯用 Python 来演示,因为它最贴近自然语言。

class Dog:
    """狗类——所有狗的蓝图"""
    
    def __init__(self, name, color, weight):
        self.name = name      # 属性:名字
        self.color = color    # 属性:毛色
        self.weight = weight  # 属性:体重
    
    def bark(self):
        """方法:叫"""
        print(f"{self.name} 汪汪叫!")
    
    def run(self):
        """方法:跑"""
        print(f"{self.name} 跑起来了,毛色是{self.color}的")

# 创建对象
wangcai = Dog("旺财", "黄色", 15)
xiaobai = Dog("小白", "白色", 8)

# 调用方法
wangcai.bark()   # 输出:旺财 汪汪叫!
xiaobai.run()    # 输出:小白 跑起来了,毛色是白色的

看到了吗?Dog 是类,wangcaixiaobai 是对象。它们各自有各自的属性,互不干扰。这就是面向对象最基础的思想——把数据和操作数据的方法打包在一起

1.3 面向对象的三大特性概览

说到面向对象,绕不开三大特性:封装、继承、多态。我当年面试的时候,被问烂了。但真正理解它们,是在实际项目中踩了坑之后。

1.3.1 封装:把秘密藏起来

封装,说白了就是把不该暴露的东西藏起来。你开车的时候,踩油门就行,不需要知道发动机里活塞怎么转的。

代码里也一样。有些内部数据和方法,外部不应该直接碰。我曾经接手过一个项目,所有属性都是公开的,结果到处都在改同一个数据,查 bug 查了三天——嗯,从那以后我写类必加私有属性。

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.__balance = balance  # 私有属性,外部不能直接访问
    
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
    
    def get_balance(self):
        return self.__balance

# 外部只能通过方法操作,不能直接改 __balance
account = BankAccount("张三", 1000)
account.deposit(500)
print(account.get_balance())  # 1500

小技巧:Python 里用双下划线开头(如 __balance)表示私有属性。虽然技术上还是能绕过去,但约定俗成——看到双下划线,就别碰。

1.3.2 继承:站在巨人的肩膀上

继承解决的是代码复用的问题。你写了一个「动物」类,有吃、睡、动这些通用方法。然后你写「狗」类、「猫」类,难道要把这些方法再写一遍?

没必要。让狗和猫继承动物类就行了。

class Animal:
    def eat(self):
        print("正在吃东西...")
    
    def sleep(self):
        print("正在睡觉...")

class Dog(Animal):  # 继承 Animal
    def bark(self):
        print("汪汪!")

class Cat(Animal):  # 继承 Animal
    def meow(self):
        print("喵喵!")

dog = Dog()
dog.eat()   # 继承来的方法
dog.bark()  # 自己的方法

我个人的习惯是:继承层次不要超过三层。超过三层,代码就变得像俄罗斯套娃,改底层一个方法,上面全受影响。我在一个老项目里见过七层继承——改一个基类,崩了二十几个子类,那场面...

避坑指南:我曾经以为「多用继承显得很高级」,结果维护成本直线上升。后来学乖了:能用组合(把一个类作为另一个类的属性)解决的问题,就别用继承。

1.3.3 多态:同一个接口,不同的行为

多态这个词听起来玄乎,其实很简单:同一个方法名,在不同对象上表现不同

比如「叫」这个方法。狗叫是「汪汪」,猫叫是「喵喵」,牛叫是「哞哞」。你不需要关心它是什么动物,只需要知道它能「叫」就行。

class Animal:
    def make_sound(self):
        pass  # 父类不实现,留给子类

class Dog(Animal):
    def make_sound(self):
        print("汪汪!")

class Cat(Animal):
    def make_sound(self):
        print("喵喵!")

def animal_sound(animal):
    animal.make_sound()  # 不管传进来的是狗还是猫,都能叫

animals = [Dog(), Cat()]
for a in animals:
    animal_sound(a)  # 输出:汪汪! 喵喵!

你想想看,如果没有多态,你得写一堆 if type(animal) == Dog 这样的判断。代码又臭又长,加一个新动物还得改判断逻辑。多态让代码对扩展开放,对修改关闭——这就是设计模式里开闭原则的精髓。

1.4 本章知识体系总览

说了这么多,咱们用一张图把核心逻辑串起来。我特意画了这张 SVG,方便你一眼看清整个知识结构。

面向对象编程核心知识体系 面向对象编程 基本概念 类(Class)→ 蓝图 对象(Object)→ 实例 属性(Attribute)→ 特征 方法(Method)→ 行为 三大特性 封装(Encapsulation) 继承(Inheritance) 多态(Polymorphism) 实践要点 类 = 蓝图,对象 = 实例 继承层次 ≤ 3 层 多用组合,少用继承 开闭原则:对扩展开放

1.5 小结

这一章咱们把面向对象最核心的概念过了一遍。说白了就是三句话:

  • 是模板,对象是实物
  • 封装藏好内部秘密,继承复用已有代码,多态让接口统一
  • 写代码的时候,多想想现实世界是怎么建模的

我个人觉得,面向对象与其说是一种编程技术,不如说是一种思维方式。你开始用「对象」的眼光去看待问题的时候,代码自然就清晰了。

好,这一章就到这儿。下一章咱们深入聊聊类与对象的内存模型——搞清楚对象在内存里到底长什么样,很多疑惑就迎刃而解了。


公众号:蓝海资料掘金营,微信 deep3321