1、面向对象编程介绍
面向对象(object-oriented ;简称: OO) 至今还没有统一的概念 我这里把它定义为: 按人们 认识客观世界的系统思维方式,采用基于对象(实体) 的概念建立模型,模拟客观世界分析、设 计、实现软件的办法。
面向对象编程(Object Oriented Programming-OOP) 是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近相似的操作逻辑和操作 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。
面向对象的理解:
- 面向对象是一种设计思想
1. 符合人们的思考习惯
2. 把执行者变成指挥者
3. 简化功能,把复杂的事情简单化
- 想完成一个事,找具有这样功能的对象
- 如果能找到,调用这个对象的功能,完成这个事
- 如果找不到,创建具有这样功能的对象,再调用完成这个事
面向对象有三大特征:
1. 封装
2. 继承
3. 多态
2、类和对象
面向对象编程的2个非常重要的概念:类和对象
对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类
类就相当于制造飞机时的图纸,用它来进行创建的飞机就相当于对象
- 类是对事务的描述,是抽象的。
- 对象是类的具体体现。
- 类对事务的描述:属性(名词)和行为(动词)
2.1类
具有相同属性和行为事物的统称
2.2对象
某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的
2.3类和对象之间的关系
小总结:类就是创建对象的模板
2.4类的构成
- 类(Class) 由3个部分构成
- 类的名称:类名
- 类的属性:一组数据 属性、变量
- 类的方法:允许对进行操作的方法 (行为) 方法
2.5类的抽象
拥有相同(或者类似)属性和行为的对象都可以抽像出一个类
3、定义类
类是对事务的描述。
1、属性
2、行为
现在呢,要描述汽车这个类。
1、类名 Car 大驼峰命名法
2、属性
3、行为(语法与函数一样,这里叫方法) 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))
4、创建对象
#创建类
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)
5、__ init__()魔法方法
在上一小节的demo中,我们已经给BMW这个对象添加了2个属性,wheelNum(车的轮胎数量)以及color(车的颜色),试想如果再次创建一个对象的话,肯定也需要进行添加属性,显然这样做很费事,那么有没有办法能够在创建对象的时候,就顺便把车这个对象的属性给设置呢?
- [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解释器会自动把当前的对象引用传递进去
6、__ 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没有返回值,报错)
7、理解self
- self表示是当前对象,可以理解为自己
- 可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思
- 某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可
8、应用:烤地瓜
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再次测试
定义类:
属性
1、cookedLevel int 0
2、cookedString str '生的'
3、condiments [] []
方法
1、初始化属性 __init__ cookedLevel,cookedString,condiments
2、烤地瓜 cook time
3、加调料 addCondiment condiment
4、地瓜的信息 __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分钟-----
- 烤成灰了 地瓜(番茄酱)
- ------接下来要添加配料-芥末酱------
- 烤成灰了 地瓜(番茄酱,芥末酱)
9、应用:存放家具
home类:
属性
1、面积
方法
2、存放家具
bed类:
属性:
1、面积
2、名字
#定义一个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)
- 如果一个对象与另外一个对象有一定的关系,那么一个对象可用是另外一个对象的属性
10、保护对象的属性(私有属性)
如果有一个对象,当需要对其进行修改属性时,有2种方法
对象名.属性名 = 数据 ---->直接修改
对象名.方法名() ---->间接修改
为了更好的保存属性安全,即不能随意修改,一般的处理方式为
将属性定义为私有属性
添加一个可以调用的方法,供调用
私有化某些敏感的数据属性,
对外提供可访问的接口(方法),
这也是一种封装
在java,C#中,要求:
1、所有的属性私有化
2、对外提供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())
11、__ 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......')
12、继承介绍以及单继承
将共性的内容放在父类中,子类只需要关注自己特有的内容
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()
总结
- 私有的属性,不能通过对象直接访问,但是可以通过方法访问
- 私有的方法,不能通过对象直接访问
- 私有的属性、方法,不会被子类继承,也不能被访问
- 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
13、多继承
多继承:这个类继承了多个父类,是有顺序
继承具有传递性
继承之后,此对象的方法或属性就增加。
调用的时候,注意是否自己有,或者父类有。
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'>)
14、重写
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))
15、多态
- 所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。
首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。
在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。
python既可以说支持多态,也可以说不支持多态
1、支持多态
python的弱类型,变量的类型是根据赋值的类型判断的,值是什么类型,变量就是什么类型
这就是多态
2、不支持多态
因为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)
16、类属性、实例属性
- 直接在类中定义的,与方法平齐,不在方法里的属性就是 类属性
- 在方法里通过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)
总结
- 如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。
17、实例方法、类方法和静态方法
17.1实例方法
实例方法/对象方法,有一个参数,一般叫self
在使用的时候,对象.方法名(实参)
self不需要手动传值,默认将当前对象传递过去给self
17.2类方法
语法:
@classmethod
def 方法名(cls,x,y,z...):
语句
调用:
对象名.
类名.
cls:类对象
类也是对象,type的对象,
在类方法中,设置的属性,是类属性,所有对象共享。
什么时候用类方法呢?
1、想通过类直接访问的方法
2、想通过方法来设置或者修改类属性
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
- 静态方法中不需要额外定义参数
- 因此在静态方法中引用类属性的话,必须通过类对象来引用
18、设计模式
18.1设计模式的六大原则
-
设计模式六大原则(1):单一职责原则
即一个类只负责一项职责
-
设计模式六大原则(2):里氏替换原则
所有引用基类的地方必须能透明地使用其子类的对象
-
设计模式六大原则(3):依赖倒置原则
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
-
设计模式六大原则(4):接口隔离原则
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
-
设计模式六大原则(5):迪米特法则
一个对象应该对其他对象保持最少的了解。尽量降低类与类之间的耦合。
-
设计模式六大原则(6):开闭原则
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
18.2分类
1.创建型模式
主要目的:创建对象
共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
2.结构型模式
主要目的:对象的组成和对象的关系
共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
3.行为型模式
主要目的:对象的行为,对象能做什么
共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
19、工厂设计模式
组成:
- 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品
- 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
- 具体产品角色:工厂类所创建的对象就是此角色的实例。
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店只负责销售,汽车厂只负责制造
总结:
对象创建比较复杂的时候,可以考虑使用简单工厂
- 优点:
在简单工厂中主函数或者客户端不再负责对象的创建,而是把这个责任交给工厂类,主函数或者客户端在使用对象的时候只从工厂中调用就行了,从而明确了各个类的职责,符合单一职责原则) - 缺点:
由于这个工厂类负责所有对象的创建,那么当子类增多时,我们就需要去修改工厂类的代码,这样呢,就违反了一个原则:开闭原则
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如果需要增加一个具体产品类角色,需要添加这个类和对应的工厂类。代码量大。
20、new魔法方法的使用
a1 = A()
创建对象的步骤
1、首先调用__new__得到一个对象
2、调用__init__为对象添加属性
3、将对象赋值给变量
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方法就是在有原材料的基础上,加工,初始化商品环节
21、单例设计模式(单列模式Singleton)
21.1单例是什么
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。
21.2创建单例-保证只有1个对象
1、单例模式Singleton
在项目中某些对象,只有一个,可以一直使用。
如果再次实例化,会很占资源和时间。
所以,这样的对象就需要设计成单例模式。
2、原型模式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