02.OOP面向對象-1.面向對象介紹

一、面向對象編程介紹

面向對象(object-oriented ;簡稱: OO) 至今尚未統一的概念 我這裏把它定義爲: 按人們 認識客觀世界的系統思惟方式,採用基於對象(實體) 的概念創建模型,模擬客觀世界分析、設 計、實現軟件的辦法。java

面向對象編程(Object Oriented Programming-OOP) 是一種解決軟件複用的設計和編程方法。 這種方法把軟件系統中相近類似的操做邏輯和操做 應用數據、狀態,以類的型式描述出來,以對象實例的形式在軟件系統中複用,以達到提升軟件開發效率的做用。python

面向對象的理解:
- 面向對象是一種設計思想
1. 符合人們的思考習慣
2. 把執行者變成指揮者
3. 簡化功能,把複雜的事情簡單化

- 想完成一個事,找具備這樣功能的對象
- 若是能找到,調用這個對象的功能,完成這個事
- 若是找不到,建立具備這樣功能的對象,再調用完成這個事
面向對象有三大特徵:
1. 封裝
2. 繼承
3. 多態

二、類和對象

面向對象編程的2個很是重要的概念:類和對象數據庫

對象是面向對象編程的核心,在使用對象的過程當中,爲了將具備共同特徵和行爲的一組對象抽象定義,提出了另一個新的概念——類編程

類就至關於製造飛機時的圖紙,用它來進行建立的飛機就至關於對象設計模式

- 類是對事務的描述,是抽象的。
- 對象是類的具體體現。
- 類對事務的描述:屬性(名詞)和行爲(動詞)

2.1類

具備相同屬性和行爲事物的統稱安全

2.2對象

某一個具體事物的存在 ,在現實世界中能夠是看得見摸得着的app

2.3類和對象之間的關係

小總結:類就是建立對象的模板函數

2.4類的構成

  • 類(Class) 由3個部分構成
  1. 類的名稱:類名
  2. 類的屬性:一組數據 屬性、變量
  3. 類的方法:容許對進行操做的方法 (行爲) 方法

2.5類的抽象

擁有相同(或者相似)屬性和行爲的對象均可以抽像出一個類測試

三、定義類

類是對事務的描述。
    一、屬性
    二、行爲

如今呢,要描述汽車這個類。
    一、類名        Car   大駝峯命名法
    二、屬性
    三、行爲(語法與函數同樣,這裏叫方法)     run  stop   
        至少有一個參數,名字任意,通常都是self

對象是類的具體體現
建立對象

名字 = 類()
class Car:

    def run(self):
        print('汽車奔跑中。。。。。。')

    def stop(self):
        print('汽車急剎中。。。。。。')


wlhgs = Car()
wlhgs.run()
wlhgs.stop()

bcs = Car()
bm7 = Car()
ad8 = Car()
#每次建立都是新的對象
print(wlhgs,id(wlhgs))
print(bcs,id(bcs))


#雖然每一個對象都有類裏方法,可是實際上是一個方法,地址同樣。
print(id(wlhgs.run))
print(id(bcs.run))

四、建立對象

#建立類
class Car:

    def run(self):
        print('汽車奔跑中。。。。。。')

    def stop(self):
        print('汽車急剎中。。。。。。')


def haha(self):
    print('哈哈。。。。。。。')

#建立對象-實例    
bmw = Car()
#調用/執行實例方法
bmw.run()
#爲對象實例設置一個屬性
bmw.color = '黑色'
#獲取對象實例的屬性
print('顏色:%s'%(bmw.color))
bmw.brand = '寶馬7系'
print('系列:%s'%(bmw.brand))


aodi = Car()
#此時aodi對象實例並無color屬性
#print(aodi.color)

五、__ init__()魔法方法

在上一小節的demo中,咱們已經給BMW這個對象添加了2個屬性,wheelNum(車的輪胎數量)以及color(車的顏色),試想若是再次建立一個對象的話,確定也須要進行添加屬性,顯然這樣作很費事,那麼有沒有辦法可以在建立對象的時候,就順便把車這個對象的屬性給設置呢?this

  • [x] 答:init()方法

5.1使用方法

在python中相似於這樣格式__名字__()的方法叫作魔法方法

__init___
做用:
    在對象建立的時候爲對象添加屬性--實例屬性
特色:
    在建立對象的時候,自動會被調用


self:當前對象實例,哪一個對象調用了這個方法,self就是哪一個對象

5.2__init__()方法的調用

class Car:
    def __init__(self):
        print('__init__......')
        self.color = '黑色'
        self.brand = '哈弗H6'

    def run(self):
        print('汽車奔跑中。。。。。。%s,%s'%(self,id(self)))

    def stop(self):
        print('汽車急剎中。。。。。。')

# 
#mumaren = Car()
#mumaren.run()
#print('%s,%s'%(mumaren,id(mumaren)))

haval1 = Car()
print(haval1.color)
print(haval1.brand)

haval2 = Car()
print(haval2.color)
print(haval2.brand)

5.3建立對象的時候同時初始化屬性

class Car:
    def __init__(self,color,brand):
        print('__init__......')
        self.color = color
        self.brand = brand

    def run(self):
        print('汽車奔跑中。。。。。。%s,%s'%(self,id(self)))

    def stop(self):
        print('汽車急剎中。。。。。。')


haval1 = Car('白色','哈弗h7')
print(haval1.color)
print(haval1.brand)


haval2 = Car('銀灰色','哈弗h9')
print(haval2.color)
print(haval2.brand)

#對象是可變類型
haval3 = haval2
haval3.color = '黑色'
print(haval2.color)

5.4總結

  • 當建立Car對象後,在沒有調用__init__()方法的前提下,BMW就默認擁有了2個屬性wheelNum和color,緣由是__init__()方法是在建立對象後,就馬上被默認調用了
  • init()方法,在建立一個對象時默認被調用,不須要手動調用
  • init(self)中,默認有1個參數名字爲self,若是在建立對象時傳遞了2個實參,那麼__init__(self)中除了self做爲第一個形參外還須要2個形參,例如__init__(self,x,y)
  • init(self)中的self參數,不須要開發者傳遞,python解釋器會自動把當前的對象引用傳遞進去

六、__ str__()魔法方法

5.1定義__str__()方法

__str__

何時調用? 對象轉換成字符串   str(對象)  測試的時候,打印對象的信息

格式: 
    def __str__(self):
        return 字符串

print打印的時候,默認就將內容轉成字符串

6.2__str__()方法的調用

class Car:
    def __init__(self,color,brand):
        print('__init__......')
        self.color = color
        self.brand = brand
    
    def __str__(self):
        print('__str__......')
        return 'Car color:%s,brand:%s'%(self.color,self.brand)

    def run(self):
        print('汽車奔跑中。。。。。。')

    def stop(self):
        print('汽車急剎中。。。。。。')
    
    def show(self):
        print('color:%s,brand:%s'%(self.color,self.brand))
    

haval1 = Car('白色','哈弗h7')

print(haval1)
print(id(haval1))
#print(str(haval1))
#haval1.show()

6.3總結

  • 在python中方法名若是是__xxxx__()的,那麼就有特殊的功能,所以叫作「魔法」方法
  • 當使用print輸出對象的時候,只要本身定義了__str__(self)方法,那麼就會打印從在這個方法中return的數據(若是__str__沒有返回值,報錯)

七、理解self

- self表示是當前對象,能夠理解爲本身
- 能夠把self當作C++中類裏面的this指針同樣理解,就是對象自身的意思
- 某個對象調用其方法時,python解釋器會把這個對象做爲第一個參數傳遞給self,因此開發者只須要傳遞後面的參數便可

八、應用:烤地瓜

8.1分析’烤地瓜‘的屬性和方法

示例屬性以下:

  • cookedLevel : 這是數字;0~3表示仍是生的,超過3表示半生不熟,超過5表示已經烤好了,超過8表示已經烤成木炭了!咱們的地瓜開始時時生的
  • cookedString : 這是字符串;描述地瓜的生熟程度
  • condiments : 這是地瓜的配料列表,好比番茄醬、芥末醬等

示例方法以下:

  • cook(): 把地瓜烤一段時間
  • addCondiments(): 給地瓜添加配料
  • init(): 設置默認的屬性
  • str(): 讓print的結果看起來更好一些

8.2定義類,而且定義__init__()方法

#定義`地瓜`類
class SweetPotato:
    '這是烤地瓜的類'

    #定義初始化方法
    def __init__(self):
        self.cookedLevel = 0
        self.cookedString = "生的"
        self.condiments = []

8.3添加’烤地瓜‘方法

#烤地瓜方法
    def cook(self, time):
        self.cookedLevel += time
        if self.cookedLevel > 8:
            self.cookedString = "烤成灰了"
        elif self.cookedLevel > 5:
            self.cookedString = "烤好了"    
        elif self.cookedLevel > 3:
            self.cookedString = "半生不熟"
        else:
            self.cookedString = "生的"

8.4基本功能已有,測試

  • 添加如下代碼測試
mySweetPotato = SweetPotato()
print(mySweetPotato.cookedLevel)
print(mySweetPotato.cookedString)
print(mySweetPotato.condiments)

8.5測試cook方法是否好用

  • 在上面的代碼最後面添加以下代碼
print("------接下來要進行烤地瓜了-----")
mySweetPotato.cook(4) #烤4分鐘
nt(mySweetPotato.cookedLevel)
print(mySweetPotato.cookedString)

運行結果爲:

  • 0
  • 生的
  • []
  • ------接下來要進行烤地瓜了-----
  • 4
  • 半生不熟

8.6定義addCondiments()方法和__str__()方法

def __str__(self):
        msg = self.cookedString + " 地瓜"
        if len(self.condiments) > 0:
            msg = msg + "("
            for temp in self.condiments:
                msg = msg + temp + ", "
            msg = msg.strip(", ")

            msg = msg + ")"
        return msg

def addCondiments(self, condiments):
    self.condiments.append(condiments)

8.7再次測試

定義類:
  屬性
    一、cookedLevel           int                 0
    二、cookedString          str                 '生的'
    三、condiments            []                  []
  方法
    一、初始化屬性         __init__            cookedLevel,cookedString,condiments
    二、烤地瓜               cook                time
    三、加調料               addCondiment        condiment
    四、地瓜的信息         __str__

完整的代碼以下:

class SweetPotato:
    "這是烤地瓜的類"

    #定義初始化方法
    def __init__(self):
        self.cookedLevel = 0
        self.cookedString = "生的"
        self.condiments = []

    #定製print時的顯示內容
    def __str__(self):
        msg = self.cookedString + " 地瓜"
        if len(self.condiments) > 0:
            msg = msg + "("

            for temp in self.condiments:
                msg = msg + temp + ", "
            msg = msg.strip(", ")

            msg = msg + ")"
        return msg

    #烤地瓜方法
    def cook(self, time):
        self.cookedLevel += time
        if self.cookedLevel > 8:
            self.cookedString = "烤成灰了"
        elif self.cookedLevel > 5:
            self.cookedString = "烤好了"    
        elif self.cookedLevel > 3:
            self.cookedString = "半生不熟"
        else:
            self.cookedString = "生的"

    #添加配料
    def addCondiments(self, condiments):
        self.condiments.append(condiments)

# 用來進行測試
mySweetPotato = SweetPotato()
print("------有了一個地瓜,尚未烤-----")
print(mySweetPotato.cookedLevel)
print(mySweetPotato.cookedString)
print(mySweetPotato.condiments)
print("------接下來要進行烤地瓜了-----")
print("------地瓜經烤了4分鐘-----")
mySweetPotato.cook(4) #烤4分鐘
print(mySweetPotato)
print("------地瓜又經烤了3分鐘-----")
mySweetPotato.cook(3) #又烤了3分鐘
print(mySweetPotato)
print("------接下來要添加配料-番茄醬------")
mySweetPotato.addCondiments("番茄醬")
print(mySweetPotato)
print("------地瓜又經烤了5分鐘-----")
mySweetPotato.cook(5) #又烤了5分鐘
print(mySweetPotato)
print("------接下來要添加配料-芥末醬------")
mySweetPotato.addCondiments("芥末醬")
print(mySweetPotato)

運行結果爲:

  • ------有了一個地瓜,尚未烤-----
  • 0
  • 生的
  • []
  • ------接下來要進行烤地瓜了-----
  • ------地瓜經烤了4分鐘-----
  • ------地瓜又經烤了3分鐘-----
  • 半生不熟 地瓜
  • ------接下來要添加配料-番茄醬------
  • 烤好了 地瓜(番茄醬)
  • ------地瓜又經烤了5分鐘-----
  • 烤成灰了 地瓜(番茄醬)
  • ------接下來要添加配料-芥末醬------
  • 烤成灰了 地瓜(番茄醬,芥末醬)

九、應用:存放傢俱

home類:
  屬性
    一、面積
  方法
    二、存放傢俱

bed類:
  屬性:
    一、面積
    二、名字
#定義一個home類
class Home:

    def __init__(self, area):
        self.area = area #房間剩餘的可用面積
        #self.light = 'on' #燈默認是亮的
        self.containsItem = []

    def __str__(self):
        msg = "當前房間可用面積爲:" + str(self.area)
        if len(self.containsItem) > 0:
            msg = msg + " 容納的物品有: "
            for temp in self.containsItem:
                msg = msg + temp.getName() + ", "
            msg = msg.strip(", ")
        return msg

    #容納物品
    def accommodateItem(self,item):
        #若是可用面積大於物品的佔用面積
        needArea = item.getUsedArea()
        if self.area > needArea:
            self.containsItem.append(item)
            self.area -= needArea
            print("ok:已經存放到房間中")
        else:
            print("err:房間可用面積爲:%d,可是當前要存放的物品須要的面積爲%d"%(self.area, needArea))


#定義bed類
class Bed:

    def __init__(self,area,name = '牀'):
        self.name = name
        self.area = area

    def __str__(self):
        msg = '牀的面積爲:' + str(self.area)
        return msg

    #獲取牀的佔用面積
    def getUsedArea(self):
        return self.area

    def getName(self):
        return self.name


#建立一個新家對象
newHome = Home(100)#100平米
print(newHome)

#建立一個牀對象
newBed = Bed(20)
print(newBed)

#把牀安放到家裏
newHome.accommodateItem(newBed)
print(newHome)

#建立一個牀對象
newBed2 = Bed(30,'席夢思')
print(newBed2)

#把牀安放到家裏
newHome.accommodateItem(newBed2)
print(newHome)
  • 若是一個對象與另一個對象有必定的關係,那麼一個對象可用是另一個對象的屬性

十、保護對象的屬性(私有屬性)

若是有一個對象,當須要對其進行修改屬性時,有2種方法

對象名.屬性名 = 數據 ---->直接修改

對象名.方法名() ---->間接修改

爲了更好的保存屬性安全,即不能隨意修改,通常的處理方式爲

將屬性定義爲私有屬性
添加一個能夠調用的方法,供調用

私有化某些敏感的數據屬性,
對外提供可訪問的接口(方法),
這也是一種封裝

在java,C#中,要求:

一、全部的屬性私有化
二、對外提供get,set

python沒要求。

若是某些屬性就是不讓外部訪問,直接__屬性名 私有化
是否提供對外訪問的接口,根據須要。
class Person:

    def __init__(self):
        self.__age = 18

    def getAge(self):
        #判斷一些業務邏輯,若是符號要去,給你數據,不符合,不給。
        return self.__age;

    def setAge(self,age):
        if age<0 or age>120:
            print('年齡不符合要求。。。。。。')
        else:
            self.__age = age


laowang = Person()
print(laowang.getAge())
laowang.setAge(-40)
print(laowang.getAge())

十一、__ del__()魔法方法(瞭解便可)
建立對象後,python解釋器默認調用init()方法;

當刪除一個對象時,python解釋器也會默認調用一個方法,這個方法爲__del__()方法

import time

class Animal:
    # 初始化方法
    # 建立完對象後會自動被調用
    def __init__(self, name):
        print('__init__方法被調用')
        self.__name = name

    #對象在被垃圾回收機制的時候調用這個方法,來釋放資源。除非有特殊要求,通常不要重寫。
    #在關閉數據庫鏈接對象的時候,能夠在這裏,釋放資源
    def __del__(self):
        print('__del__......')

wangcai = Animal('旺財')
xiaoqiang = wangcai

del wangcai
print('*'*50)
del xiaoqiang

time.sleep(10)

print('over......')

十二、繼承介紹以及單繼承

將共性的內容放在父類中,子類只須要關注本身特有的內容
python中全部的內容都是對象,全部的對象都直接或間接繼承了object

12.1繼承的概念

在程序中,繼承描述的是事物之間的所屬關係,例如貓和狗都屬於動物,程序中即可以描述爲貓和狗繼承自動物

12.2單繼承

將共性的內容放在父類中

子類只關注本身特有的內容

擴展性高,代碼更簡潔

# 定義一個父類
class Dog(object):
    def __init__(self,name,color):
        self.name = name
        self.color = color

    def run(self):
        print('%s %s run......'%(self.name,self.color))
# 定義一個子類,繼承Dog類
class TaiDi(Dog):
    def setName(self,name):
        self.name = name

taidi = TaiDi('泰迪','棕色')
taidi.run() #泰迪 棕色 run......

taidi.setName('泰迪弟')
taidi.run() #泰迪弟 棕色 run......

總結

  • 子類在繼承的時候,在定義類時,小括號()中爲父類的名字
  • 父類的屬性、方法,會被繼承給子類

12.3私有的不能被繼承

class Animal(object):

    def __init__(self, name='動物', color='白色'):
        self.__name = name
        self.color = color

    def __test(self):
        print(self.__name)
        print(self.color)

    def test(self):
        print(self.__name)
        print(self.color)



class Dog(Animal):
    def dogTest1(self):
        #print(self.__name) #不能訪問到父類的私有屬性
        print(self.color)


    def dogTest2(self):
        #self.__test() #不能訪問父類中的私有方法
        self.test()


A = Animal()
#print(A.__name) #程序出現異常,不能訪問私有屬性
print(A.color)
#A.__test() #程序出現異常,不能訪問私有方法
A.test()

print("------分割線-----")

D = Dog(name = "小花狗", color = "黃色")
D.dogTest1()
D.dogTest2()

總結

  • 私有的屬性,不能經過對象直接訪問,可是能夠經過方法訪問
  • 私有的方法,不能經過對象直接訪問
  • 私有的屬性、方法,不會被子類繼承,也不能被訪問
  • 通常狀況下,私有的屬性、方法都是不對外公佈的,每每用來作內部的事情,起到安全的做用

1三、多繼承

多繼承:這個類繼承了多個父類,是有順序

繼承具備傳遞性

繼承以後,此對象的方法或屬性就增長。
調用的時候,注意是否本身有,或者父類有。
class A(object):
    def a(self):
        print('a......')

class B:
    def b(self):
        self.c()  #這裏又調用C()中的c
        print('b......')

class C(A,B):
    def c(self):
        print('c......')

# 
#laowang = C()
#laowang.a()
#laowang.b()
#laowang.c()

x = C()
x.b() #c......
      #b......

#獲取父類
print(C.__bases__) #(<class '__main__.A'>, <class '__main__.B'>)
print(A.__bases__) #(<class 'object'>,)

#列舉,這個類和繼承類的結構。調用方法的順序**(類名.__mro__)**
print(C.__mro__)   #(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

1四、重寫

14.1重寫父類方法

所謂重寫,就是子類中,有一個和父類相同名字的方法,在子類中的方法會覆蓋掉父類中同名的方法

class A(object):
    def haha(self):
        print('haha a......')

class B(A):
    def haha(self):
        print('哈哈 b......')
    
b = B()
b.haha()

14.2調用父類的方法

  • 子類覆蓋父類,有兩種方法能夠調用父類的方法
class C2:
    def haha(self):
        print('haha 2......')
    

class C3:
    def haha(self):
        print('haha 3......')


class C4(C3,C2):
    def haha(self):
        #super().haha()
        C2.haha(self)
        print('haha 4......')


laowang= C4()
laowang.haha()
print(C4.__mro__)
class Fu:
    def __init__(self,name,age):
        print('fu...%s'%(id(self)))
        self.name = name
        self.age = age

class Zi(Fu):
    def __init__(self,name,age,sex):
        print('zi...%s'%(id(self)))
        #super().__init__(name,age)   #這是方法一
        Fu.__init__(self,name,age)    #這是方法二
        self.sex = sex
        
    def show(self):
        print('%s,%s,%s'%(self.name,self.age,self.sex))


zi = Zi('老王',43,'男')
zi.show()
print(id(zi))

1五、多態

  • 所謂多態:定義時的類型和運行時的類型不同,此時就成爲多態

多態的概念是應用於Java和C#這一類強類型語言中,而Python崇尚「鴨子類型」。

首先Python不支持多態,也不用支持多態,python是一種多態語言,崇尚鴨子類型。

在程序設計中,鴨子類型(英語:duck typing)是動態類型的一種風格。在這種風格中,一個對象有效的語義,不是由繼承自特定的類或實現特定的接口,而是由當前方法和屬性的集合決定。

python既能夠說支持多態,也能夠說不支持多態


    一、支持多態
        python的弱類型,變量的類型是根據賦值的類型判斷的,值是什麼類型,變量就是什麼類型
        這就是多態

    二、不支持多態
        由於python是弱類型語言,沒有要求類型,不徹底符合多態的定義。
class F1(object):
    def show(self):
        print('F1.show')

class S1(F1):
    def show(self):
        print('S1.show')

class S2(F1):
    def show(self):
        print('S2.show')

def func(obj):
    obj.show()
    #print(type(obj))


s1_obj = S1()
func(s1_obj) 

s2_obj = S2()
func(s2_obj)

f1 = F1()
func(f1)

1六、類屬性、實例屬性

  • 直接在類中定義的,與方法平齊,不在方法裏的屬性就是 類屬性
  • 在方法裏經過self.屬性 都是實例屬性

16.1類屬性

class People(object):
    name = 'Tom'  #公有的類屬性
    __age = 12     #私有的類屬性

p = People()

print(p.name)           #正確
print(People.name)      #正確
print(p.__age)         #錯誤,不能在類外經過實例對象訪問私有的類屬性
print(People.__age)    #錯誤,不能在類外經過類對象訪問私有的類屬性

16.2實例屬性(對象屬性)

class People(object):
    address = '山東' #類屬性
    def __init__(self):
        self.name = 'xiaowang' #實例屬性
        self.age = 20 #實例屬性

p = People()
p.age =12        #實例屬性
print(p.address) #正確
print(p.name)    #正確
print(p.age)     #正確

print(People.address) #正確
print(People.name)    #錯誤
print(People.age)     #錯誤

16.3經過實例(對象)去修改類屬性

class People(object):
    country = 'china' #類屬性


print(People.country)
p = People()
print(p.country)
p.country = 'japan' 
print(p.country)      #實例屬性會屏蔽掉同名的類屬性
print(People.country)
del p.country    #刪除實例屬性
print(p.country)

總結

  • 若是須要在類外修改類屬性,必須經過類對象去引用而後進行修改。若是經過實例對象去引用,會產生一個同名的實例屬性,這種方式修改的是實例屬性,不會影響到類屬性,而且以後若是經過實例對象去引用該名稱的屬性,實例屬性會強制屏蔽掉類屬性,即引用的是實例屬性,除非刪除了該實例屬性。

1七、實例方法、類方法和靜態方法

17.1實例方法

實例方法/對象方法,有一個參數,通常叫self
在使用的時候,對象.方法名(實參)
self不須要手動傳值,默認將當前對象傳遞過去給self

17.2類方法

語法:

@classmethod
def 方法名(cls,x,y,z...):
    語句


調用:
    對象名.
    類名.

cls:類對象


類也是對象,type的對象,

在類方法中,設置的屬性,是類屬性,全部對象共享。



何時用類方法呢?
    一、想經過類直接訪問的方法
    二、想經過方法來設置或者修改類屬性
class People(object):
    country = 'china'

    #類方法,用classmethod來進行修飾
    @classmethod
    def getCountry(cls):
        return cls.country

    @classmethod
    def setCountry(cls,country):
        cls.country = country


p = People()

print(p.getCountry())     #china    #能夠用過實例對象引用
print(People.getCountry())#china        #能夠經過類對象引用

p.setCountry('japan')   

print(p.getCountry())     #japan

17.3靜態方法

語法:
    @staticmethod
    def 名(形參):
        語句

    實例方法必須至少有一個參數放在第一個,通常叫self
    類方法必須至少有一個參數放在第一個,通常叫cls

    靜態方法能夠沒有參數,也能夠有參數,可是沒法直接獲取類對象和實例對象
    因此通常靜態方法裏的功能,不與對象相關
class Dog:
    age = 18

    def __init__(self,name):
        self.name = name

    @staticmethod
    def show():
        print('show.....%s'%(Dog.age))

d = Dog('旺財')
d.show()   #show.....18

- 靜態方法中不須要額外定義參數
- 所以在靜態方法中引用類屬性的話,必須經過類對象來引用

1八、設計模式

18.1設計模式的六大原則

  1. 設計模式六大原則(1):單一職責原則

    即一個類只負責一項職責
  2. 設計模式六大原則(2):里氏替換原則

    全部引用基類的地方必須能透明地使用其子類的對象
  3. 設計模式六大原則(3):依賴倒置原則

    高層模塊不該該依賴低層模塊,兩者都應該依賴其抽象;抽象不該該依賴細節;細節應該依賴抽象。
  4. 設計模式六大原則(4):接口隔離原則

    客戶端不該該依賴它不須要的接口;一個類對另外一個類的依賴應該創建在最小的接口上。
  5. 設計模式六大原則(5):迪米特法則

    一個對象應該對其餘對象保持最少的瞭解。儘可能下降類與類之間的耦合。
  6. 設計模式六大原則(6):開閉原則

    一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。

18.2分類

1.建立型模式

主要目的:建立對象
共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。

2.結構型模式

主要目的:對象的組成和對象的關係
共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

3.行爲型模式

主要目的:對象的行爲,對象能作什麼
共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。

1九、工廠設計模式

組成:

  1. 工廠類角色:這是本模式的核心,含有必定的商業邏輯和判斷邏輯,用來建立產品
  2. 抽象產品角色:它通常是具體產品繼承的父類或者實現的接口。
  3. 具體產品角色:工廠類所建立的對象就是此角色的實例。

19.1簡單工廠模式

實例:

'''
    抽象角色(父類):它通常是具體產品繼承的父類或者實現的接口
'''
class Car(object):
    def move(self):
        pass
    def stop(self):
        pass

'''
    具體產品角色(繼承抽象角色):工廠類所建立的對象就是此角色的實例。
'''
class H1(Car):
    def move(self):
        print('哈弗h1 move......')
        
    def stop(self):
        print('哈弗h1 stop......')


class H9(Car):
    def move(self):
        print('哈弗h9 move......')
        
    def stop(self):
        print('哈弗h9 stop......')

class H7(Car):
    def move(self):
        print('哈弗h7 move......')
        
    def stop(self):
        print('哈弗h7 stop......')

class H6(Car):
    def move(self):
        print('哈弗h6 move......')
        
    def stop(self):
        print('哈弗h6 stop......')


'''
    工廠類角色:這是本模式的核心,含有必定的邏輯判斷,用來建立產品
'''
class CarFactory:
    @classmethod
    def createCar(cls,name):
        car = None
        if name=='哈弗H1':
            car = H1()
        elif name=='哈弗H9':
            car = H9()
        elif name=='哈弗H7':
            car = H7()
        elif name=='哈弗H6':
            car = H6()
        return car

'''
    主代碼
'''
name = input('請輸入要購買的車型:')
car = CarFactory.createCar(name)
if car!=None:
    car.move()
    car.stop()
else:
    print('沒有。。。。。。。')

說明:
工廠函數、工廠類對具體的生成環節進行了封裝,這樣有利於代碼的後需擴展,即把功能劃分的更具體,4s店只負責銷售,汽車廠只負責製造

總結:
對象建立比較複雜的時候,能夠考慮使用簡單工廠

  1. 優勢:
    在簡單工廠中主函數或者客戶端再也不負責對象的建立,而是把這個責任交給工廠類,主函數或者客戶端在使用對象的時候只從工廠中調用就好了,從而明確了各個類的職責,符合單一職責原則)
  2. 缺點:
    因爲這個工廠類負責全部對象的建立,那麼當子類增多時,咱們就須要去修改工廠類的代碼,這樣呢,就違反了一個原則:開閉原則

19.2工廠方法模式

'''
    抽象角色(父類):它通常是具體產品繼承的父類或者實現的接口
'''
class Car(object):
    def move(self):
        pass
    def stop(self):
        pass

'''
    具體產品角色(繼承抽象角色):工廠類所建立的對象就是此角色的實例。
'''
class H1(Car):
    def move(self):
        print('哈弗h1 move......')
        
    def stop(self):
        print('哈弗h1 stop......')


class H9(Car):
    def move(self):
        print('哈弗h9 move......')
        
    def stop(self):
        print('哈弗h9 stop......')

class H7(Car):
    def move(self):
        print('哈弗h7 move......')
        
    def stop(self):
        print('哈弗h7 stop......')

'''
    抽象工廠類角色
'''

class CarFactory:
    @classmethod
    def createCar(cls,name):
        pass
    

'''
    具體工廠類角色:這是本模式的核心,含有必定的邏輯判斷,用來建立產品
'''
class H1Factory(CarFactory):
    @classmethod
    def createCar(cls,name):    
        return H1()

class H9Factory(CarFactory):
    @classmethod
    def createCar(cls,name):    
        return H9() 

class H7Factory(CarFactory):
    @classmethod
    def createCar(cls,name):    
        return H7() 
'''
    主代碼
'''
name = input('請輸入要購買的車型:')
car = None

if name=='哈弗H1':
    car = H1Factory.createCar(name)
elif name=='哈弗H9':
    car = H9Factory.createCar(name)

if car!=None:
    car.move()
    car.stop()
else:
    print('沒有。。。。。。。')

總結:
工廠方法模式的優勢和缺點

  1. 優勢:
    解決了簡單工廠模式的違反開閉原則
  2. 缺點:
    1若是須要增長一個具體產品類角色,須要添加這個類和對應的工廠類。代碼量大。

20、__new__魔法方法的使用

a1 = A()

建立對象的步驟
一、首先調用__new__獲得一個對象
二、調用__init__爲對象添加屬性
三、將對象賦值給變量
class A(object):
    def __init__(self):
        print("這是 init 方法")

    def __new__(cls):
        print(id(cls))
        print("這是 new 方法")  
        return object.__new__(cls)
    
    
a1 = A()
print(a1)
#7214424
#這是 new 方法
#這是 init 方法
#<__main__.A object at 0x0000000000BDEB00>
print(id(a1)) #12446464
print(id(A))  #7214424

總結

  • __new__至少要有一個參數cls,表明要實例化的類,此參數在實例化時由Python解釋器自動提供
  • __new__必需要有返回值,返回實例化出來的實例,這點在本身實現__new__時要特別注意,能夠return父類__new__出來的實例,或者直接是object的__new__出來的實例
  • __init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上能夠完成一些其它初始化的動做,__init__不須要返回值
  • 咱們能夠將類比做製造商,__new__方法就是前期的原材料購買環節,__init__方法就是在有原材料的基礎上,加工,初始化商品環節

2一、單例設計模式(單列模式Singleton)

21.1單例是什麼

確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例,這個類稱爲單例類,單例模式是一種對象建立型模式。

21.2建立單例-保證只有1個對象

一、單例模式Singleton
        在項目中某些對象,只有一個,能夠一直使用。
        若是再次實例化,會很佔資源和時間。
        因此,這樣的對象就須要設計成單例模式。

二、原型模式Prototype
        能夠實例化多個對象,每一個都是新的,之前設計的類都是原型模式


object.__new__(cls):
        表示建立了一個實例對象
class Singleton:
    #表示對象是否被建立 None:沒有,其它:已經建立
    __instance = None
    def __new__(cls):
        if cls.__instance == None:
            cls.__instance = object.__new__(cls)

        return cls.__instance



s1 = Singleton()
s2 = Singleton()
s3 = Singleton()
print(id(s1))   #18342968
print(id(s2))   #18342968
print(id(s3))   #18342968

21.3不定長參數

class Singleton:
    #表示對象是否被建立 None:沒有,其它:已經建立
    __instance = None
    #表示是否是第一次調用init:        True:第一次調用  False:不是第一次調用
    __firstInit = True
    def __init__(self,*args,**kwargs):
        if Singleton.__firstInit:
            self.args = args
            self.kwargs = kwargs
            Singleton.__firstInit=False
    def __new__(cls,*args,**kwargs):
        if cls.__instance == None:
            cls.__instance = object.__new__(cls)

        return cls.__instance



s1 = Singleton('老王',10,'add','',money=12345)
print(id(s1))       #8514472
print(s1.args[0])   #老王
print(s1.args[2])   #add
print(s1.kwargs['money'])#12345

s2 = Singleton('旺財')
print(id(s2))       #8514472
print(s2.args[0])   #老王
print(s2.args[2])   #add
print(s2.kwargs['money'])#12345

s3 = Singleton()
print(s3.kwargs['money'])#12345
相關文章
相關標籤/搜索