• 面向对象之组合与封装


    一  组合

    解决类与类之间代码的冗余问题有两种方式:

        1)继承:继承是类与类之间什么是什么的关系,是一种从属关系,子类从属于父类。

        2)组合:类与类之间的关系,是一种什么有什么的关系,一个类产生的对象,该对象有一个属性,这个属性的值来自另一个对象。也即是说在一个类中以另一个类的对象作为数据属性,称为类的组合。

    下面我们用一个实例来说明下:

    class Equip: #武器装备类
    ...     def fire(self):
    ...         print('release Fire skill')
    ... 
    >>> class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
    ...     camp='Noxus'
    ...     def __init__(self,nickname):
    ...         self.nickname=nickname
    ...         self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性
    ... 
    >>> r1=Riven('锐雯雯')
    >>> r1.equip.fire() #可以使用组合的类产生的对象所持有的方法
    release Fire skill
    View Code
    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    class Course:
        def __init__(self,name,period,price):
            self.name=name
            self.period=period
            self.price=price
        def tell_info(self):
            print('<%s %s %s>' %(self.name,self.period,self.price))
    
    class Teacher(People):
        def __init__(self,name,age,sex,job_title):
            People.__init__(self,name,age,sex)
            self.job_title=job_title
            self.course=[]
            self.students=[]
    
    
    class Student(People):
        def __init__(self,name,age,sex):
            People.__init__(self,name,age,sex)
            self.course=[]
    
    
    egon=Teacher('egon',18,'male','沙河霸道金牌讲师')
    s1=Student('牛榴弹',18,'female')
    
    python=Course('python','3mons',3000.0)
    linux=Course('python','3mons',3000.0)
    
    #为老师egon和学生s1添加课程
    egon.course.append(python)
    egon.course.append(linux)
    s1.course.append(python)
    
    #为老师egon添加学生s1
    egon.students.append(s1)
    
    
    #使用
    for obj in egon.course:
        obj.tell_info()
    View Code

    当类与类之间显著不同的时候,我们可以可以用组合的方式,减少代码的冗余。

    二  封装

    我们从字面上来理解封装:就是用一个袋子把一些东西装进去然后把袋子系起来,这样就做到了封装。

    我们可以把封装看成一个简单的隐藏,只是改变了隐藏对象的外形,其实实质没变。

    其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形
    类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式
    
    class A:
        __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
        def __init__(self):
            self.__X=10 #变形为self._A__X
        def __foo(self): #变形为_A__foo
            print('from A')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.
    
    如果我们一定要从外部访问也是可以访问到的,使用A._A__N是可以访问到的,这种,在外部是无法通过__x这个名字访问到。

    那么这种变形我们要注意三个问题:

        1)这种封装并不能真正的限制我们从外部直接访问,只是要改变访问方式:_类名__属性,然后就可以访问到这个属性。

        2)这种语法意义上的变形,只在类定义阶段发生一次,类定义之后,新增的以__开头的属性都没有变形的效果。

       3)如果父类不想让子类覆盖自己的方法,可以在方法前加__开头。

    封装数据:

    我们上面说封装是一种隐藏,其实严格意义上他不算隐藏,封装的目的是用来被调用的,所以还是要被外部调用,但是只是换了一种方式,不是直接调用而是在调用的过程加上一些限制条件,来完成对于数据属性操作的严格控制。

    class Teacher:
        def __init__(self,name,age):
            # self.__name=name
            # self.__age=age
            self.set_info(name,age)
    
        def tell_info(self):
            print('姓名:%s,年龄:%s' %(self.__name,self.__age))
        def set_info(self,name,age):
            if not isinstance(name,str):
                raise TypeError('姓名必须是字符串类型')
            if not isinstance(age,int):
                raise TypeError('年龄必须是整型')
            self.__name=name
            self.__age=age
    
    
    t=Teacher('egon',18)
    t.tell_info()
    
    t.set_info('egon',19)
    t.tell_info()

    封装方法:(封装函数属性)

    比如我们的相机,为我们提供了拍照功能,其实在拍照的过程中,相机会自动调节一些饱和度,曝光度等,只是我们将这些功能封装起来而已。

    提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。

    取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
    对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
    隔离了复杂度,同时也提升了安全性
    
    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()
    
    a=ATM()
    a.withdraw()

     

  • 相关阅读:
    monads-are-elephants(转)
    程序语言简史(转)
    语法的省略不能造成编译器的歧义
    scala getter and setter
    隐式类型转换
    java 调用 scala
    列表的操作
    Scala HandBook
    Scala 高级编程练习
    Net 2.0 C# 专用的只读类Tuple
  • 原文地址:https://www.cnblogs.com/zhangsanfeng/p/8824624.html
Copyright © 2020-2023  润新知