设计模式之创建型模式
创建型模式主要是用于创建对象时使用的设计模式。
一、简单工厂
简单工厂模式又叫静态工厂方法模式,工厂模式家族中最简单的一种模式。这个模式的基本工作方式: 通过一个工厂来决定创建哪种具体的产品实例。
简单工厂模式的好处是可以将产品对象的细节封装在其实现类的内部,改变一个产品对象具体实现不会影响其他产品。可扩展性强,当需要新增产品类型时,只需要添加对应的实现类,然后修改工厂,增加一个判断分支即可。修改工厂函数带来的风险比较低。
class OperAdd():
def get_result(self,a,b):
return a+b
class OperSub():
def get_result(self,a,b):
return a-b
class OperMul():
def get_result(self,a,b):
return a*b
class OperDiv():
def get_result(self,a,b):
return a/b
class SimpleFactory():
def create_operator(self,operator):
if operator=='+':
return OperAdd()
elif operator=='-':
return OperSub()
elif operator=='*':
return OperMul()
elif operator=='/':
return OperaDiv()
sf = SimpleFactory()
op = sf.create_operator('+')
print op.get_result(4,1)
二、工厂模式
简单工厂模式很简单,也使得客户端不需要写过多得代码,只需要输入一个条件,然后逻辑判断交给服务端代码来做。但当我们想要加一个分支的时候,就要原工厂类,这违背了一个原则:即开放-关闭原则(关闭指的是不可以对原来的类进行任何的修改)。工厂模式解决了这个缺点。它的思想是一个子类对应一个工厂类,然后让客户端去决定使用哪一个子类。不过工厂模式的缺点是一个子类对应一个工厂类,增加了开发量。
这里有一点要说明,为什么还要麻烦写工厂类,直接就使用类就行了嘛。这里就和之前在简单工厂提到的那样,我们不希望将类直接暴露给客户,而是给他一个封装好的工厂类。
代码:
class LeiFeng():
2 def sweep(self):
3 print 'leifeng'
4
5
6 class Student(LeiFeng):
7 def sweep(self):
8 print 'student'
9
10 class Vol(LeiFeng):
11 def sweep(self):
12 print 'vol'
13
14
15
16 class StuFact():
17
18 def Create(self):
19 s = Student()
20 return s
21
22
23 class VolFact():
24
25 def Create(self):
26 v = Vol()
27 return v
28
29
30 if __name__ == "__main__":
31
32 s = StuFact()
33 st = s.Create()
34 st.sweep()
35
36 v =VolFact().Create()
37 v.sweep()
38
工厂方法模式用的还是比较多的。比如Mybatis的SqlSessionFactory,Spring的BeanFactory。
Mybatis的SqlSessionFactory在获取SqlSession时就使用了工厂方法:
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return openSessionFromDataSource(execType, null, autoCommit);
}
我们来看一下SqlSessionFactory的实现类DefaultSqlSessionFactory如何获取SqlSession的。
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
最重要的就是这句:final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
通过环境变量获取TransactionFactory,TransactionFactory可能有不同的实现,我们通过某种方式获取到对应实现类。
在spring种,随处可见各种Factory,工厂模式的使用非常广泛。其中IoC的核心BeanFactory,其实就是个简单工厂模式。Springboot使用的是ApplicationContext(也是继承BeanFactory),通过beanName调用getBean可获得bean。
三、抽象工厂:
抽象工厂是工厂方法的进一步演进。如果只有一个产品那么就相当于工厂方法。抽象工厂其实用的不多。
class Department():
2 #interface
3 def queryp(self):
4 print 'leifeng'
5
6
7 class MySQLDepart(Department):
8 #productorA1
9 def query(self):
10 print 'student'
11
12 class OracleDepart(Department):
13 #productorA2
14 def query(self):
15 print 'vol'
16
17
18 class User():
19 #interfaceB
20 def query(self):
21 print 'damn'
22
23 class MySQLUser(User):
24 #productorB1
25 def query(self):
26 print 'shit'
27
28 class OracleUser(User):
29 #productorB2
30 def query(self):
31 print 'baby'
32
33
34
35
36 class MySQLFact():
37 #creator
38 def create_user(self):
39 s = MySQLUser()
40 return s
41 def create_depart(self):
42 return MySQLDepart()
43
44
45
46 class OracleFact():
47 #creator
48 def create_user(self):
49 v = OracleUser()
50 return v
51 def create_depart(self):
52 return OracleDepart()
四、单例模式:
单例模式是一种比较常用的设计模式,它主要是保证一个类只有一个实例存在,并提供它的一个全局访问点。比如一个Django项目中有一个配置类,存在了全局的配置信息。我现在只希望创建一个实例,供整个项目引用。
其实在Python中,并不需要特意去写单例模式,因为Python处处都是单例模式,因为在一个Python文件中调用另外一个module,就是单例模式,只调用一次。将你所需要的属性和方法,直接暴露在模块中变成模块的全局变量和方法即可!当第一次import的时候,会生成一个.pyc文件,等下次或者其他模块引用该模块时,会自动加载pyc。
当然,如果也想像其他语言一样写单例模式的话,有很多种形式。我就用__new__来实现,主要是想说一下__new__和__init__的区别。
__init__大家都是特别熟悉的了,当我们创建实例的时候,执行__init__进行初始化,那么__new__是干什么的呢?
其实当我们创建实例的时候,__new__才是第一个被调用的方法,__new__方法会调用__init__方法, __new__用来生成实例,__init__是实例创建后对实例进行初始化。它的用法是:__new__(cls,*args),第一个参数是类,其他的参数都要传给__init__,其实这种方法很不常用。我们今天就用该方法创建的单个实例。
class SingleClass(object):
def __new__(cls,*args):
if not hasattr(cls,'instance'):
cls.instance = super(SingleClass,cls).__new__(cls,*args)
return cls.instance
def __init__(*args):
for i in args:
print i
s = SingleClass(1,3)
单例分为懒汉式和饿汉式,这个在JAVA中经常遇见或者面试也经常被问到。
可通过静态类、DCL、枚举等方式来实现懒汉式单例模式的创建。
建造者模式
当构造参数比较多的时候,就可以使用建造者模式,通过建造者模式来创建对象。lombok种的Builder就是典型的建造者模式。
比如某个类Test使用了Builder注解,可以通过 Test.builder.build()创建实例。
下面的是一个简单的例子:
public class Creator {
private String name;
private String gender;
private Integer age;
private Integer height;
public Creator(Builder builder){
this.name = builder.name;
this.age = builder.age;
this.gender = builder.gender;
this.height = builder.height;
}
public static Builder builder(){
return new Builder();
}
public static class Builder {
private String name;
private String gender;
private Integer age;
private Integer height;
public Creator build(){
return new Creator(this);
}
public Builder setName(String name){
this.name = name;
return this;
}
private Builder setAge(Integer age){
this.age = age;
return this;
}
private Builder setGender(String gender){
this.gender = gender;
return this;
}
private Builder setHeight(Integer height){
this.height = height;
return this;
}
}
public static void main(String[] args){
Creator creator = Creator.builder()
.setAge(10)
.setName("test")
.setHeight(13)
.build();
}
}
原型模式:通过clone获得的实例,比如深拷贝或者浅拷贝。
微信分享/微信扫码阅读