1. 程式人生 > >面向對象之組合、封裝、多態性、鴨子類型

面向對象之組合、封裝、多態性、鴨子類型

冗余 self. hello 復雜度 obj 語法 帶來 anim 安全

一、組合

1. 什麽是組合

一個對象的屬性是來自於另外一個類的對象,稱之為組合

2. 為何用組合

組合也是用來解決類與類代碼冗余的問題

3. 如何用組合

# class Foo:
#     aaa=1111
#     def __init__(self,x,y):
#         self.x=x
#         self.y=y
#
#     def func1(self):
#         print(‘Foo內的功能‘)
#
#
# class Bar:
#     bbb=2222
#     def __init__(self, m, n):
#         self.m = m
# self.n = n # # def func2(self): # print(‘Bar內的功能‘) # # obj1=Foo(10,20) # obj2=Bar(30,40) # # obj1.xxx=obj2 #組合的使用方法 # # # print(obj1.x,obj1.y,obj1.aaa,obj1.func1) # print(obj1.xxx.m,obj1.xxx.n,obj1.xxx.bbb,obj1.xxx.func2)

conclusion:

當類之間有顯著不同,並且較小的類是較大的類所需要的組件時,用組合比較好

二、封裝

1. 什麽是封裝


裝指的是把屬性裝進一個容器
封指的是隱藏的意思,但是這種隱藏式對外不對內的

2. 為何要封裝
封裝不是單純意義的隱藏
封裝數據屬性的目的:將數據屬性封裝起來,類 外部的使用就無法直接操作該數據屬性了
需要類 內部開一個接口給使用者,類的設計者可以在接口之上附加任意邏輯,從而嚴格
控制使用者對屬性的操作
封裝函數屬性的目的:隔離復雜度

3. 如何封裝?
只需要在屬性前加上__開頭,該屬性就會被隱藏起來,該隱藏具備的特點:
1. 只是一種語法意義上的變形,即__開頭的屬性會在檢測語法時發生變形_類名__屬性名
2. 這種隱藏式對外不對內的,因為在類內部檢測語法時所有的代碼統一都發生的變形


3. 這種變形只在檢測語法時發生一次,在類定義之後新增的__開頭的屬性並不會發生變形
4. 如果父類不想讓子類覆蓋自己的屬性,可以在屬性前加__開頭

class Foo:
    __x=111 #_Foo__x
    def __init__(self,m,n):
        self.__m=m # self._Foo__m=m
        self.n=n

    def __func(self): #_Foo__func
        print(Foo.func)

    def func1(self):
        print(self.__m) #self._Foo__m
        print(self.__x) #self._Foo__x

# print(Foo.__dict__)
# Foo.__x
# Foo.__func
# print(Foo._Foo__x)
# print(Foo._Foo__func)

封裝數據屬性的真實意圖:

1、封裝數據:

class Peoole:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def tell_info(self):
        print(<name:%s age:%s>%(self.name,self.age))

    def set_info(self,new_name,new_age):
        if type(new_name) is not str:
            print(名字必須是str類型)
            return
        if type(new_age) is not int:
            print(年齡必須是int類型)
            return
        self.name = new_name
        self.age = new_age

    def clear_info(self):
        del self.name


  people1 = Peoole(wwl,18)
  people2 = Peoole(wlw,20)
  #
  people1.tell_info()
  people2.tell_info()
  #
  people1.set_info(leilei,30)
  print(people1.tell_info())
  #
  people2.clear_info()

2、封裝方法:目的是隔離復雜度

# 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()
取款是功能,而這個功能有很多功能組成:插卡、密碼認證、輸入金額、打印賬單、取錢
對使用者來說,只需要知道取款這個功能即可,其余功能我們都可以隱藏起來,
很明顯這麽做
隔離了復雜度,同時也提升了安全性

*了解裝飾器property的用法
1、什麽是property?
property是一種特殊的屬性,訪問它時會執行一段功能(函數)然後返回值
2、為何用?

將一個類的函數定義成特性以後,對象再去使用的時候obj.bim,根本無法察覺自己的bim
執行了一個函數然後計算出來的,這種特性的使用方式遵循了統一訪問的原則
eg:
‘‘‘
例一:BMI指數(bmi是計算而來的,但很明顯它聽起來像是一個屬性而非方法,如果我們將其做成一個屬性,更便於理解)

成人的BMI數值:
過輕:低於18.5
正常:18.5-23.9
過重:24-27
肥胖:28-32
非常肥胖, 高於32
  體質指數(BMI)=體重(kg)÷身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86
‘‘‘
# class People:
#     def __init__(self,name,weight,height):
#         self.name=name
#         self.weight=weight
#         self.height=height
#
#     @property
#     def bmi(self):
#         return self.weight / (self.height ** 2)
#
# obj=People(‘egon‘,70,1.82)
# obj.height=1.85
#
# print(obj.bmi)

3、怎麽用

新寫法:

# class People:
#     def __init__(self,name):
#         self.__name=name
#
#     @property
#     def name(self):
#         return ‘<name:%s>‘ %self.__name
#
#     @name.setter
#     def name(self,new_name):
#         if type(new_name) is not str:
#             print(‘名字必須是str類型‘)
#             return
#         self.__name=new_name
#
#     @name.deleter
#     def name(self):
#         del self.__name
#
# obj=People(‘egon‘)
# print(obj.name)
#
# # obj.name=123
# # print(obj.name)
#
# del obj.name
# print(obj.__dict__)

舊寫法:

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

    def xxx_name(self):
        return <name:%s> %self.__name

    def yyy_name(self,new_name):
        if type(new_name) is not str:
            print(名字必須是str類型)
            return
        self.__name=new_name

    def zzz_name(self):
        del self.__name

    name=property(xxx_name,yyy_name,zzz_name) #以前的寫法,且函數名的位置不能改變

obj=People(egon)
print(obj.name)

# obj.name=123
# print(obj.name)

del obj.name
print(obj.__dict__)

三、多態性

1. 什麽是多態
同一種事物的多種形態

2. 為何要用多態
多態性:指的是可以在不用考慮對象具體類型的前提下而直接使用對象下的方法

3. 如何用多態

# import abc
#
# class Animal(metaclass=abc.ABCMeta):
#     @abc.abstractmethod
#     def speak(self):
#         pass
#
# # Animal() # 父類不能實例化,因為父類本身就是用來制定標準的
# class People(Animal):
#     def speak(self):
#         print(‘say hello‘)
#      def jiao(self):
#        print(‘say hello‘)
#
# class Dog(Animal):
#      def speak(self):
#         print(‘汪汪汪‘)
#
# class Pig(Animal):
#      def speak(self):
#         print(‘哼哼哼‘)
#
#
# peo=People()
# dog1=Dog()
# pig1=Pig()
# #
# #
# peo.speak()
# dog1.speak()
# pig1.speak()
 def speak(animal):
    animal.speak()

speak(peo)
speak(dog1)
speak(pig1)

四、鴨子類型

Python崇尚鴨子類型,即‘如果看起來像、叫聲像而且走起路來像鴨子,那麽它就是鴨子

python程序員通常根據這種行為來編寫程序。例如,如果想編寫現有對象的自定義版本,可以繼承該對象

也可以創建一個外觀和行為像,但與它無任何關系的全新對象,後者通常用於保存程序組件的松耦合度。

#二者都像鴨子,二者看起來都像文件,因而就可以當文件一樣去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass
class Memory:
    def read(self):
        print(mem read)

    def write(self):
        print(mem write)

class Disk:
    def read(self):
        print(disk read)

    def write(self):
        print(disk write)

class Cpu:
    def read(self):
        print(cpu read)

    def write(self):
        print(cpu write)


obj1=Memory()
obj2=Disk()
obj3=Cpu()

obj1.read()
obj2.read()
obj3.read()

其實我們一直在享受著多態性帶來的好處,比如Python的序列類型有多種形態:字符串,列表,元組,多態性體現如下

#str,list,tuple都是序列類型
s=str(hello)
l=list([1,2,3])
t=tuple((4,5,6))

#我們可以在不考慮三者類型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)

面向對象之組合、封裝、多態性、鴨子類型