面向对象之封装

发布时间:2024年01月04日

【 一 】面向对象的三大特性

  • 面向对象编程有三大特性:
    • 封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)
  • 其中最重要的一个特征就是封装。
    • 封装指的就是把数据与功能都整合到一起

? ? ? ? 当然:封装不仅仅是把数据和功能组合在一起,更重要的是要对外部世界隐藏实体的实现细节,提供合理的接口和访问权限,保证程序的可维护性、安全性。

【 1 】什么是封装

?????????在程序设计中,封装(Encapsulation)是一种面向对象编程的特性,它不仅仅是对具体对象的抽象,更是对数据和行为的抽象,它将数据和方法封装在一个实体中,对外部世界隐藏实体内部的复杂性,只暴露必要的接口供外部使用。

私有化:

? ? ? ? 封装就不得不提私有化?Private Encapsulation)是指将类的某些属性或方法设置为私有访问权限,使其只能在类内部被访问和修改,而不能被外部程序直接访问。

????????通过将属性或方法设置为私有(private),可以实现对类内部实现细节的隐藏,避免外部程序对类的内部状态进行非法访问或修改,从而提高程序的安全性和稳定性。私有化可以有效地封装类的内部实现,使得外部程序只能通过公共接口来与类进行交互。

在面向对象编程中,私有属性或方法通常使用访问修饰符 private 来标识,它们只能在类的内部被访问和修改。这样可以确保类的内部状态不会被外部程序随意修改,而只能通过公共接口提供的方法来操作和获取数据。

例如,一个银行账户类中的密码属性可以被私有化,外部程序无法直接访问和修改密码,只能通过提供的公共方法来验证密码或修改密码。这样可以保护用户的隐私和账户安全。

私有化的优点包括:

  1. 封装内部实现细节,提高代码的安全性和稳定性。
  2. 隐藏类的内部状态,减少对外部的暴露,提高代码的可维护性和扩展性。
  3. 提供更精确的访问权限控制,防止外部程序的非法访问和修改。
  4. 可以灵活地改变类的内部实现,而不会对外部程序造成影响。

????????总之,私有化是封装特性的一部分,它通过限制外部程序对类的访问权限来保护类的内部实现,提高代码的安全性和稳定性。

【 2 】为什么要封装

  • 封装数据的主要原因是:保护隐私(把不想别人知道的东西封装起来)

【 3 】封装的方法

????????封装的方法是指将类中的行为(方法)封装在类的内部,通过公共接口(公共方法)来对外暴露和调用。

????????封装的方法通常使用访问修饰符来标识其访问权限,常见的修饰符包括 public、private 和 protected。

  1. 公共方法(public methods):公共方法是类的公开接口,可以被外部程序直接访问和调用。公共方法被声明为 public 访问修饰符,可以在类的内部和外部被访问和调用。

  2. 私有方法(private methods):私有方法是类的私有接口,只能在类的内部被访问和调用。私有方法被声明为 private 访问修饰符,外部程序无法直接访问和调用私有方法。

  3. 受保护方法(protected methods):受保护方法是类的受保护接口,只能在类的内部和其子类中被访问和调用。受保护方法被声明为 protected 访问修饰符,外部程序无法直接访问和调用受保护方法。

????????通过封装方法,可以将类的内部实现隐藏起来,只暴露必要的公共接口。这样可以提高代码的安全性和稳定性,同时也使得类的使用更加简单和清晰。外部程序只需要通过公共方法来与类进行交互,而不需要了解类的具体实现细节。

????????总结起来,封装的方法是将类的行为封装在类的内部,通过公共接口来对外暴露和调用。这种封装的方式可以提高代码的安全性和稳定性,同时也提供了一种清晰、简洁的方式来与对象进行交互。

【 二 】隐藏属性

????????隐藏属性的方法是通过将类的属性设置为私有(private)访问权限来实现的。私有属性只能在类的内部被访问和修改,外部程序无法直接访问和修改私有属性。

????????隐藏属性的方法可以确保类的内部状态不会被外部程序随意修改,只能通过公共接口提供的方法来操作和获取数据。这样可以保护对象的数据完整性和安全性,并减少对外部的暴露。

隐藏属性的方法步骤如下:

  1. 将属性声明为私有:在类中将需要隐藏的属性声明为私有,使用 private 访问修饰符标识,例如 private int age;。

  2. 提供公共方法:在类中提供公共方法(getters 和 setters)来操作和获取私有属性的值。公共方法被声明为公共访问修饰符(public),可以被外部程序访问和调用。

    • Getter 方法(访问器):用于获取私有属性的值,通常以 get 开头,例如 public int getAge() { return age; }。

    • Setter 方法(修改器):用于设置私有属性的值,通常以 set 开头,例如 public void setAge(int age) { this.age = age; }。

????????通过提供公共方法来操作私有属性,可以实现对属性的控制和验证。例如,在 Setter 方法中可以添加验证逻辑,确保赋予属性的值满足一定的条件,如年龄不能为负数。

????????隐藏属性的方法可以保护对象的数据,防止外部程序对属性的非法访问和修改。同时,公共方法还提供了一种清晰、统一的方式来与对象进行交互,使得代码更易读和维护。

实例:?定义属性就是为了使用,所以隐藏并不是目的

class YinCan:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name

    def get_age(self):
        return self.__age

    def set_age(self,age):
        if age >= 0:
            self.__age = age
        else:
            print('年龄不能为为负数!')

# 创建Person 对象并使用公告方法操作隐藏属性
person = YinCan('maodada',26)
print(person.get_name()) # maodada
print(person.get_age()) # 26

person.set_name("BOB")
person.set_age(30)
print(person.get_name()) # BOB
print(person.get_age()) # 30

person.set_age(-56) # 年龄不能为为负数!

小总结:

name和_name以及__name的实例

class Person:
    def __init__(self,name):
        self.name = name # 公共属性
        self._name = name # 受保护
        self.__name = name # 私有属性

    def get_name(self):
        return self.name

# 创建 Person对象
person = Person('xidada')
print(person.name) # xidada

print(person._name) # xidada

print(person.__name) # AttributeError: 'Person' object has no attribute '__name'. Did you mean: '_name'?

在上面的例子中,我们使用了三种不同的命名方式来表示属性的可访问性。

  • self.name:这是最简单的方式,属性没有任何特殊的命名规则。外部程序可以直接访问和修改这个属性。

  • self._name:这是一种约定俗成的命名方式,以单下划线开头表示属性是受保护的,外部程序可以访问这个属性,但是建议遵守惯例,尽量使用公共的getter和setter方法来访问和修改属性。

  • self.__name:这是一种使用双下划线开头的命名方式,表示属性是私有的。私有属性只能在类的内部访问,外部程序无法直接访问。在示例中,我们使用get_private_name()方法在类的内部间接访问私有属性。

????????需要注意的是,以双下划线开头的属性名会进行名称修饰(name mangling)以避免命名冲突。在类的外部,我们无法直接访问__name属性,会导致AttributeError错误。

????????总结起来,name属性是公共的,_name属性是受保护的,__name属性是私有的。根据属性的可访问性需求,选择适当的命名方式来表示属性的访问权限。

【 三 】装饰器property

【 1 】什么是property

  • property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

【 2 】使用方法和具体实例? ? ? ?

?在Python中,property是一种特殊的装饰器,它允许你将一个方法转换为一个属性,从而实现对该属性的访问和修改。通过使用property装饰器,可以自定义属性的读取、写入和删除行为,并提供更加灵活的访问控制。

????????使用property装饰器时,需要定义一个getter方法、一个setter方法和一个deleter方法(可选)。这些方法分别用于获取属性的值、设置属性的值和删除属性。

class ShiLi():
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,value):
        if value >= 0:
            self._name = value
        else:
            raise ValueError('里面的值不能为负数!')

    @name.deleter
    def name(self):
        del self._name

# 创建x对象
x = ShiLi(5)
print(x.name) # 5

x.name = 10
print(x.name) # 10

del x.name
print(x.name)
# AttributeError: 'ShiLi' object has no attribute '_name'. Did you mean: 'name'?

【3】为什么要用property

  • 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

  • 面向对象的封装有三种方式:

    • 【public】
      • 这种其实就是不封装,是对外公开的
    • 【protected】
      • 这种封装方式对外不公开
      • 但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
    • 【private】
      • 这种封装对谁都不公开

????????使用property的主要目的是为了实现对类的属性访问和修改的控制,以提供更加灵活和可靠的代码。

  1. 封装性:通过将属性的获取、设置和删除封装在方法中,可以隐藏底层实现细节,使代码更加清晰和易于维护。这样,其他代码只需要通过属性访问接口来操作属性,而不需要了解属性的具体实现。

  2. 访问控制:使用property可以为属性的读取和写入过程添加额外的逻辑。例如,可以在设置属性值之前进行验证或转换。这样,可以确保属性的值符合特定的规则,并防止无效数据的出现。

  3. 兼容性:通过property装饰器,可以将现有的方法转换为属性,而不会破坏现有的代码结构。这意味着可以在不修改现有代码的基础上,为类添加新的属性访问方式。这对于与现有代码库的兼容性和扩展性非常重要。

  4. 代码一致性和易用性:使用property可以使代码更加一致和易用。属性访问方式更接近于直接访问属性,而不是使用方法调用。这使得代

    class Rctena:
        def __init__(self, width, height):
            self._width = width # 初始化宽度
            self._height = height # 初始化高度
    
        @property
        def width(self):
            return self._width
    
        @width.setter
        def width(self, value):
            if value > 0:
                self._width = value
            else:
                raise ValueError('宽度必须大于0')
    
        @property
        def height(self):
            return self._height
    
        @height.setter
        def height(self, value):
            if value > 0:
                self._height = value
            else:
                raise ValueError('高度必须大于0')
    
    x = Rctena(10,6)
    print(x.width,x.height)
    
    
    x.height = 15
    print(x.height)  # 输出:15
    
    x.height = -5  #ValueError: 高度必须大于0

    码更加自然和简洁,同时提高了代码的可读性和可维护性。

  5. 可变性控制:通过在setter方法中添加逻辑,可以对属性的修改过程进行控制。这可以防止属性的意外修改或非法修改,并确保类的内部状态保持一致。

????????总之,使用property装饰器可以提供更好的封装性、访问控制、可兼容性、代码一致性和易用性,以及对属性修改过程的控制能力。它是一种有效的编程技术,有助于编写高质量、可维护的代码。

【 四 】封装和扩展性

????????封装指的是将类的属性和方法隐藏起来,防止外部直接访问和修改。这样可以保护类的数据和实现细节,同时提供公共接口供外部使用。通过封装,我们可以控制对类的访问,防止意外修改导致程序出错。

????????扩展性指的是在不修改原有代码的基础上,通过添加新的功能或修改现有功能来满足新需求。扩展性良好的代码可以灵活应对变化,减少代码重复和修改,提高代码的可维护性和可扩展性。

class Rectangle:
    def __init__(self, width, height):
        self._width = width  # 初始化宽度
        self._height = height  # 初始化高度

    @property
    def width(self):
        """获取矩形的宽度"""
        return self._width

    @width.setter
    def width(self, value):
        """设置矩形的宽度"""
        if value > 0:
            self._width = value
        else:
            raise ValueError("宽度必须大于0")

    @property
    def height(self):
        """获取矩形的高度"""
        return self._height

    @height.setter
    def height(self, value):
        """设置矩形的高度"""
        if value > 0:
            self._height = value
        else:
            raise ValueError("高度必须大于0")

    def area(self):
        """计算矩形的面积"""
        return self._width * self._height


x = Rectangle(10, 6)
print(x.width, x.height)  # 输出:10 6
print(x.area())  # 输出:60

x.width = 15
print(x.width)  # 输出:15
print(x.area())  # 输出:90

文章来源:https://blog.csdn.net/m0_58310590/article/details/135390616
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。