网站建设专家证书,常州建设网站,建设彩票网站如何盈利,企业网站建设费入什么科目一、说明 最近试着读Design pattern#xff0c; 不过有些概念实在太抽象了#xff0c; 整理一下自己所学抽象工厂的精神#xff0c;就是要有abstract class#xff08;not implement#xff09;#xff0c;而所有不同种类的对象#xff0c;都是继承这个abstract class 不过有些概念实在太抽象了 整理一下自己所学抽象工厂的精神就是要有abstract classnot implement而所有不同种类的对象都是继承这个abstract class但是使用者只知道interface的接口就好。
二、关于抽象类的使用案例
2.1 抽象类 很抽象吧直接举例会比较实在今天我开发了一个Qt windows appQt是跨平台的框架所以Qt假设里面有个button class
class Button:def clicked():print(clicked) 这个Button绝对不会这么简单他还要跟不同操作系统兼容所以就会有mac的buttonwindows的button我们就可以先开个抽象类
class Button(ABC):abstractmethoddef clicked(self):passclass WinButton(Button):def clicked(self):print(click winbutton)class MacButton(Button):def clicked(self): print(click macbutton) qt的interface可是非常多对象的有button还有checkbox等等这样我写程序的时候就要打self.btn WinButton这样子???,然后今天要打包到Mac上又要改成self.btn MacButton这样子是非常没有效率的...能不能把这个作业系统的环境提取出来呢???
2.2 关于工厂 白话就是我们需要一个工厂这个工厂可以帮我们呼叫下面不同的控件例如WinFactory就是要给我windows的控件
class GUIFactory(ABC):abstractmethoddef create_button(self):passabstractmethoddef create_checkbox(self):passclass WinFactory(GUIFactory):def create_button(self):return WinButton()def create_checkbox(self):return WinCheckBox() class MacFactory(GUIFactory):def create_button(self):return MacButton()def create_checkbox(self):return MacCheckBox() 换个譬喻你今天要吃大餐而有前菜主餐甜点而大餐有不同风格你不会想要这样说 主厨我要日式前菜日式主餐日式甜点。而是会想要这样说 日式主厨我要前菜、主餐、甜点。这边的日式主厨就是工厂啦主厨要会煮菜 上菜 切菜 等 这个就是抽象工厂而日式主厨西式主厨就是工厂。 那这样来看看前面的关系图怎么画 资料源 抽象工厂设计模式
2.3 完整代码
from abc import ABC, abstractmethod
class GUIFactory(ABC):abstractmethoddef create_button(self):passabstractmethoddef create_checkbox(self):pass
class WinFactory(GUIFactory):def create_button(self):return WinButton()def create_checkbox(self):return WinCheckBox()
class MacFactory(GUIFactory):def create_button(self):return MacButton()def create_checkbox(self):return MacCheckBox()
class Button(ABC):abstractmethoddef clicked(self):passclass WinButton(Button):def clicked(self):print(click winbutton)class MacButton(Button):def clicked(self):print(click macbutton)
class CheckBox(ABC):abstractmethoddef checked(self):passclass WinCheckBox(CheckBox):def checked(self):print(check wincheckbox)
class MacCheckBox(CheckBox):def checked(self):print(check maccheckbox)
class Application:def __init__(self, factory):self.button factory.create_button()self.checkbox factory.create_checkbox()if __name__ __main__:app Application(MacFactory())app.button.clicked() 注意这样子对用户而言就是Application最后call的时候传入引数Mac or Win Factory这边甚至能加个if else直接判断当前os。最后那个对用户而言 看到的都是app app.button app.checkbox 早就已经透过工厂创造好啦
2.4 总结 抽象工厂模式 对用户来说单一接口所有class需要继承abstract class。抽象工厂为你提供了一个接口 可用于创建每个系列产品的对象。 只要代码通过该接口创建对象 那么你就不会生成与应用程序已生成的产品类型不一致的产品。
设计模式
抽象工厂模式
三、什么是类工厂
3.1 类工厂定义
类工厂本质 类工厂就是一个在运行时创建类的函数。 即允许创建类时根据情况决定其属性比如根据用户输入创建属性。
类工厂函数 是一个用于创建并返回类的函数。
3.2 理解类工厂函数-函数返回一个“类”的变量
使用type创建类如下
def init(self, name):self.name name
def eat(self):pass
def go_to_vet(self):print go_to_vet
return type(Animal, (object,), {__doc__: A class representing an arbitrary animal.,__init__: init,eat: eat,go_to_vet: go_to_vet,
})这种方式的缺点
这种写法会将类Animal的函数置于和Animal同一层命名空间下不利于层次化。因此一般不使用type之间创建。如果真需要使用type则可以将其封装放入一个函数中。如下
3.3 将类的“内脏”封装到函数中
下列示例表示
def create_animal_class():def init(self, name):self.name namedef eat(self):passdef go_to_vet(self):print(self.name)return type(Animal, (object,), {__doc__: A class representing an arbitrary animal.,__init__: init,eat: eat,go_to_vet: go_to_vet,})Animal1 create_animal_class( )
dog Animal1(my dog)
dog.go_to_vet()
cat Animal1(my cat)
cat.go_to_vet()3.4 封装到函数内的class关键词 通过函数调用即可获得一个自定义创建的Animal类。使用class关键字创建效果相同 def create_animal_class():class Animal(object):def init(self, name):self.name namedef eat(self):passdef go_to_vet(self):print go_to_vetreturn AnimalAnimal create_animal_class()print Animal #class __main__.Animal3.5 编写类工厂的时机
在需要基于运行时的信息(如用户输入)创建类时需要编写类工厂 如果在编码时并不知道需要赋值给类的属性时类工厂示例创建类工厂的原因假如说是为大量不同的第三方网站提供凭据的服务则需要有多重不同的验证方式。该工厂可以根据数据库查询结果生成属性
#-*- coding:utf-8 -*-
def get_credential_class(use_proxyFalse, tfaFalse):if use_proxy:keys [service_name, email_address] # 通过代理身份验证所要的密匙else:keys [username, password]if tfa:keys.append(tfa_token)class Credential(object):expected_keys set(keys)def __init__(self, **kwargs):if self.expected_keys ! set(kwargs.keys()):raise ValueError(Keys do not match)for k, v in kwargs.items():setattr(self, k, v)return Credentialcred get_credential_class(0,0)
printcred运行结果 class ‘main.Credential’
避免类属性一致性问题处理类与实例之间属性不同的问题
class C(object):foo barclass I(object):def __init__(self):self.foo bar
print C.foo()
print I.foo() # AttributeErrorc1 C()
c2 C() c1.foo baz
print c1.foo #baz
print c2.foo # barC.foo bacon
print c1.foo #baz
print c2.foo #baconprint c1.__dict__ # {foo: baz}
print c2.__dict__ #{}print I.foo() # AttributeError原因 foo作为C的一个实例被实例化但并不作为I的属性被实例化。 由于直接访问I而不是I的实例因此__init__函数还没有被允许。 一个对象的属性查找顺序遵循首先查找实例对象自己然后是类接着是类的父类。 本质__dict__属性存储着对象的所有属性(和值) 注意一些内置的数据类型是没有__dict__属性的 int,list,dict等这些常用的数据类型是没有__dict__属性的其实这是可预料的就算给了它们dict属性也没啥用毕竟它们只是用来做数据容器的。 属性指一个对象的数据或者函数 - 属性的访问通过句话.访问属性 - 支持运行中添加和修改属性 字段类的数据变量例如namescolia 方法类里面的函数。可分为 - 实例方法第一个参数需要是self它表示一个具体的实例本身。 - 类方法用classmethod它的第一个参数不是self是cls它表示这个类本身。类方法是那些并不需要类的实例就可以执行的方法 - 静态方法用staticmethod可以无视self而将这个方法当成一个普通的函数使用 #-*- coding:utf-8 -*-
class cls:clsvar 1 #普通字段def __init__(self):self.insvar 2ins1 cls()
ins2 cls()ins1.clsvar 20
print cls.clsvar #输出结果为1
print ins1.clsvar #输出结果为20
print ins2.clsvar #输出结果为1#用类名为类变量重新赋值并打印
cls.clsvar 10
print cls.clsvar #输出结果为10
print ins1.clsvar #输出结果为20
print ins2.clsvar #输出结果为10#这次直接给实例1没有在类中定义的变量赋值
ins1.x 11
print ins1.x #输出结果为11#然后再用类名给类中没有定义的变量赋值
cls.m 21
print cls.m #输出结果为21#再创建一个实例ins3然后打印一下ins3的变量
ins3 cls()
print ins3.insvar #输出结果为2
print ins3.clsvar #输出结果为10
print ins3.m #输出结果为21
print ins3.x #报错AttributeErro四、类方法限制 class C(object):foo barclassmethoddef classfoo(cls):return cls.fooprint c1.classfoo() #bacon
print c2.classfoo() #bacon注意类方法无法访问实例属性它们并不需要一个实例但需要类本身。因此c1.classfoo使用的是类的foo而不是实例c1的foo
4.1 使用类工厂 使用时机当你继承一个现有类并且所依赖的类属性必须调整时。类工厂是生成带有重载属性的恰当子类的一种恰当方式。
class C(object):foo barclassmethoddef classfoo(cls):return cls.foodef create_C_subclass(new_foo):class SubC(C):foo new_fooreturn SubCS create_C_subclass(spam)
print S.classfoo() #spam
E create_C_subclass(eggs)
print E.classfoo() #eggs执行C子类的classfoo类方法创建类的方式返回需要的结果。
4.2 单例模式 让类工厂函数难以使用的一点是类工厂返回的是类而不是类的实例。如果一个实例则必须调用类工厂函数返回的结果才可以。单例模式是一种只允许一个实例的类模式。 类工厂示例
class C(object):foo barclassmethoddef classfoo(cls):return cls.foodef CPrime(new_foobar):if new_foo bar:return C()class SubC(C):foo new_fooreturn SubCEE CPrime(bar)
FF CPrime(bar1)
print EE #__main__.C object at 0x01777CB0
print FF #class __main__.SubC五、实例的工厂模式 工厂模式是一个在软件开发中用来创建对象的设计模式。 工厂模式包涵一个超类。这个超类提供一个抽象化的接口来创建一个特定类型的对象而不是决定哪个对象可以被创建。 为了实现此方法需要创建一个工厂类并返回所需对象。 当程序运行输入一个“类型”的时候需要创建于此相应的对象。这就用到了工厂模式。在如此情形中实现代码基于工厂模式可以达到可扩展可维护的代码。当增加一个新的类型不在需要修改已存在的类只增加能够产生新类型的子类。 简短的说当以下情形可以使用工厂模式
1.不知道用户想要创建什么样的对象2.当你想要创建一个可扩展的关联在创建类与支持创建对象的类之间。 工厂模式
根据需求产生对象。from typing import Anyclass Clothes:服装工厂类def __init__(self,name):self.name namedef create(self):passclass Lovely(Clothes):def __init__(self, name):super().__init__(name)def create(self):print(f{self.name} 生产 汉服)class Cool(Clothes):def __init__(self, name):super().__init__(name)def create(self):print(f{self.name} 生产 酷酷的、帅)class Lipstick(Clothes):def __init__(self, name):super().__init__(name)def create(self):print(f{self.name} 生产 死亡芭比粉)class Shoes(Clothes):def __init__(self, name):super().__init__(name)def create(self):print(f{self.name}生产 红色高跟鞋)class Shoes2(Clothes):def __init__(self, name):super().__init__(name)def create(self):print(f{self.name}生产 蓝色高跟鞋)class Requirement:定义一个需求类staticmethoddef creatNeed(need):if need 死亡芭比粉:return Lipstick(死亡芭比粉)elif need 酷酷的、帅:return Cool(酷酷的、帅)elif need 汉服:return Lovely(汉服)elif need 红色高跟鞋:return Shoes(红色高跟鞋)elif need 蓝色高跟鞋:return Shoes2(蓝色高跟鞋)# Requirement.creatNeed(死亡芭比粉).create()
# Requirement.creatNeed(红色高跟鞋).create()
# Requirement.creatNeed(汉服).create()with open(create.txt,r,encodingutf-8)as f_r:content f_r.read()# print(content)
Requirement.creatNeed(content).create()# class StudentNum:
# num 0
#
# classmethod
# def add_num(cls):
# cls.num 1
#
# classmethod
# def get_num(cls):
# return cls.num
#
# def __new__(cls) - Any:
# StudentNum.add_num()
# return super().__new__(cls)
#
#
# class Student(StudentNum):
# def __init__(self):
# self.name
# a Student()
# b Student()
# c Student()
# print(StudentNum.get_num())