欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

面向对象三大特性之封装

程序员文章站 2022-09-27 08:09:12
封装 不绕弯子,面向对象的编程思想有三大特性,分别是:封装、继承、多态。 其中,封装是面向对象的最基本的概念。我们之前提到,对象是一个容器,装的是数据和功能。这本身就是一种封装思想,将数据和功能封装到一个对象中。 对象封装了数据和功能,那对象(类)就有了管理数据和功能的权利,即对象或者类可以把数据和 ......

封装

不绕弯子,面向对象的编程思想有三大特性,分别是:封装、继承、多态。

其中,封装是面向对象的最基本的概念。我们之前提到,对象是一个容器,装的是数据和功能。这本身就是一种封装思想,将数据和功能封装到一个对象中。

对象封装了数据和功能,那对象(类)就有了管理数据和功能的权利,即对象或者类可以把数据和功能给隐藏起来或者开放给使用者,限制对象(类)的使用者权利,或者控制/规范使用者的使用方式。


隐藏属性

如果类的设计者不想使用者直接访问到属性,就可以将属性给隐藏起来。属性分为数据属性和功能属性,即这两类属性都可以被隐藏。

隐藏属性可以隐藏类中的共有属性和对象的私有属性。

# 使用双下划线开头命名的属性将会被隐藏
class foo:
    
    __x = 1 	# 隐藏类中的共有数据属性

    def __init__(self, name, age):
        self.__name = name		# 隐藏对象的私有属性
        self.age = age		

    def __f1(self):  			# 隐藏类内定义的函数属性
        print('from test')

    def f2(self):				# f2没有被隐藏,可以被访问到
        print(self.__x) 
        print(self.__f1)
############################################################
print(foo.__x)			# 访问不到
print(foo.__f1)			# 访问不到
print(foo.f2)			# 可以访问到
print(_foo.__x, _foo.__f1)		# 可以访问

obj = foo('xliu', 18)	# 实例化对象obj
print(obj.__name)		# 访问不到
print(obj.age)			# 可以访问到

foo.__y = 2				# 增加类foo的数据属性
print(foo.__y)			# 可以访问到

注意点

# 1 在类外部无法直接访问双下滑线开头的属性,在类内部可以访问到

# 2 在类定义阶段,双下划先开头的属性会发生变形,变为 _foo__x, _foo__f1, _foo__name, 所以在在类外无法直接通过过 .__x 的方式访问。但是可以通过变形后的 _foo__x访问。但这是没有意义的。所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。

# 3 之所以在类内部可以直接通过__x 访问,是因为__开头的属性会在检查类体代码语法时统一发生变形(类定义阶段)

# 4 这种变形操作只在检查类体语法的时候发生一次,之后再定义的__开头的属性都不会变形,所以可以直接__y访问到

开放接口

定义属性的目的是为了使用,所以隐藏属性的目的不是单纯的隐藏,而是为了更好的使用。

想要这些属性被使用,就必须提供给使用者一些接口,即没有被隐藏属性。

隐藏数据属性:将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制

class student:
    
    def __init__(self, name):
        self.__name = name

    def get_name(self):
        # 通过该接口就可以间接地访问到名字属性
        print(self.__name)

    def set_name(self, new_name):
        # 通过改接口判断用户修改的新名字是否合法;非法则修改,不合法就不修改
        if type(new_name) is not str:
            print('小垃圾,名字必须是字符串类型')
            return
        self.__name = new_name

隐藏函数/方法属性:目的是为了隔离复杂度。例如atm程序的取款功能,该功能有很多其他功能组成。比如插卡、身份认证、输入金额、打印小票、取钱等,而对使用者来说只需要开发取款这个功能接口即可,其余功能我们都可以隐藏起来。

>>> class atm:
...     def __card(self): 
...         print('插卡')
...     def __auth(self): 
...         print('用户认证')
...     def __input(self): 
...         print('输入取款金额')
...     def __print_bill(self):
...         print('打印账单')
...     def __take_money(self):
...         print('取款')
...     def withdraw(self): 
...         self.__card()
...         self.__auth()
...         self.__input()
...         self.__print_bill()
...         self.__take_money()
...
>>> obj=atm()
>>> obj.withdraw()

总结隐藏属性与开放接口:本质就是为了明确地区分内外,类内部可以修改封装内的东西而不影响外部调用者的代码;而类外部只需拿到一个接口,只要接口名、参数不变,则无论设计者如何改变内部实现代码,使用者均无需改变代码。这就提供一个良好的合作基础,只要接口这个基础约定不变,则代码的修改不足为虑。