设计模式学习(二) — 创建型模式
创建型设计模式主要是用来构建对象实例,是在对象实例创建过程中的一些经验总结;
个人主页:tuzhenyu’s page
原文地址:设计模式学习(二) — 创建型模式
(0)基本概念
创建型模式隐藏了类对象实例创建的细节,在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。
创建型模式主要包括:单例模式,工厂模式和构建器模式等;
(1)单例模式
单例模式是在全局只创建一个对象实例,对外提供单实例获取的接口;
单例模式的好处:
避免多次创建销毁对象造成的性能上的损耗;
多线程使用同一个实例,实现了线程间的资源共享;
单例模式的使用场景
- Spring容器中的Bean实例默认是单例的,ApplicationContext容器在启动时会创建Bean的单例对象保存在一个哈希表缓存中;
<bean id="date" class="java.util.Date"/>
<bean id="date" class="java.util.Date scope="singleton""/>
<bean id="date" class="java.util.Date" scope="prototype"/>
<bean id="date" class="java.util.Date default-lazy-init="true"/>
Java单例模式和Spring中Bean的单例模式
Spring中Bean的单例模式和设计模式中的单例模式还有所有不同的,Spring中的Bean的单例的生命周期和ApplicationContext容器相关的,如果在一个进程中有多个ApplicationContext容器,即便Bean是单例的也会创建多个实例;
Java单例模式一般是指进程内仅存在一个实例对象;
单例模式的线程安全问题
如果一个单例类是有状态的,也就是存在类变量时会出现线程安全问题(线程安全问题都是由类变量和全局变量引起的),因为单例对象是线程间共享的,可以对同意资源进行操作;解决线程安全一般有两种方法:锁和ThreadLocal;
Spring中的Bean默认是单例的,通过ThreadLocal解决线程安全问题;Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。
比如在Spring MVC的controller层中HttpServletRequest是单例的,并发访问时使用的是同一个HttpServletRequest实例对象,因为HttpServletRequest是请求对象的外壳,具体的请求内容被封装在ThreadLocal类型的RequestContextHolder对象内,这样就实现了HttpServletRequest单例对象的线程安全;
(2)工厂模式
- 工厂模式一般分为简单工厂模式,工厂方法模式和抽象工厂模式, 这三种模式从上到下逐步抽象,并且更具一般性。
简单工厂模式
根据自变量的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式的角色分为:工厂类Factory,抽象产品(产品父类)Product,具体产品
简单工厂模式的应用场景:
Spring的BeanFactory应用简单工厂模式,根据传入一个唯一的标识来获得bean对象,如果bean对象不存在则创建,如果已经存在则直接返回;
Netty服务端客户端启动时候需要通过启动辅助类Bootstrap或者ServerBootstrap等,在启动辅助类初始化时候需要设置通道类型NioSocketChannel或者NioServerSocketChannel等,在启动时候会结合工厂模式和反射创建通道工厂channelFactory用于创建通道实例;
工厂方法模式
工厂方法模式定义一个用于创建对象的接口,子类实现接口决定具体实例化哪个类,创建多个工厂类对应多个对象实例;
工厂方法模式角色:抽象工厂类,具体工厂类,抽象产品,具体产品
工厂方法模式使用情景:
- Spring的FactoryBean就是应用了工厂方法模式,在创建Bean实例时会先创建一个未初始化的空对象实例,然后创建一个工厂类FactoryBean将空对象实例放入中,经FactoryBean放入入singletonFactoris哈希表中,通过getObject()从工厂中获取实例;
工厂模式区别
简单工厂模式和工厂方法模式的区别:简单工厂模式中只存在一个工厂实例,通过参数从工厂中返回不同的对象实例,比如只存在一个BeanFactory;工厂方法模式存在多个工厂实例,每种对象对应一个工厂实例,比如存在多个FactoryBean实例;
工厂模式和抽象工厂模式区别:工厂模式只有一个抽象产品类,而抽象工厂模式则有多种抽象产品类;工厂模式下一个工厂实例只能产生一种抽象产品类的实例,抽象工厂模式下,一个工厂实例可以产生多种抽象产品实例;
(3)构建器模式
构建器模式是将一个复杂对象的构建过程分离,通过自由的组合构建复杂对象;对于复杂对象,使用Builder模式来替代多参数构造函数是一个比较好的实践法则;
构建器模式使用场景
- 在Netty的服务端客户端启动时候需要通过启动辅助类Bootstrap或者ServerBootstrap等,Bootstrap或者ServerBootstrap类的初始化使用Builder模式进行的;
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
ChannelFuture f = b.connect(host,port).sync();
f.channel().closeFuture().sync();
总结
创建型模式主要用来创建类对象实例,不同的情景下可以单独使用也可以组合使用单例模式,工厂模式或者构建器模式等;