单例模式三种实现方式(单例模式三种实现方式是什么)
spring主要运用那些设计模式,单例模式是怎么实现的?
设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。
今天,螃蟹在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了其设计的思想理念,才能在工作学习中运用到“无形”。
Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行内典范。好了,话不多说,开始今天的内容。
spring中常用的设计模式达到九种,我们举例说明:
第一种:简单工厂
又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。如下配置,就是在 HelloItxxz 类中创建一个 itxxzBean。
beans
bean id="singletonBean" class="com.itxxz.HelloItxxz"
constructor-arg
valueHello! 这是singletonBean!value
/constructor-arg
/ bean
bean id="itxxzBean" class="com.itxxz.HelloItxxz"
singleton="false"
constructor-arg
valueHello! 这是itxxzBean! value
/constructor-arg
/bean
/beans
第二种:工厂方法(Factory Method)
通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。
一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。
螃蟹就以工厂方法中的静态方法为例讲解一下:
import java.util.Random;
public class StaticFactoryBean {
public static Integer createRandom() {
return new Integer(new Random().nextInt());
}
}
建一个config.xm配置文件,将其纳入Spring容器来管理,需要通过factory-method指定静态方法名称
bean id="random"
class="example.chapter3.StaticFactoryBean" factory-method="createRandom" //createRandom方法必须是static的,才能找到 scope="prototype"
/
测试:
public static void main(String[] args) {
//调用getBean()时,返回随机数.如果没有指定factory-method,会返回StaticFactoryBean的实例,即返回工厂Bean的实例 ? ? ? XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("config.xml")); ? ? ? System.out.println("我是IT学习者创建的实例:"+factory.getBean("random").toString());
}
第三种:单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。
核心提示点:Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope=“?”来指定
第四种:适配器(Adapter)
在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。
Adapter类接口:Target
public interface AdvisorAdapter {
boolean supportsAdvice(Advice advice);
MethodInterceptor getInterceptor(Advisor advisor);
} MethodBeforeAdviceAdapter类,Adapter
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
第五种:包装器(Decorator)
在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。我们以往在spring和hibernate框架中总是配置一个数据源,因而sessionFactory的dataSource属性总是指向这个数据源并且恒定不变,所有DAO在使用sessionFactory的时候都是通过这个数据源访问数据库。但是现在,由于项目的需要,我们的DAO在访问sessionFactory的时候都不得不在多个数据源中不断切换,问题就出现了:如何让sessionFactory在执行数据持久化的时候,根据客户的需求能够动态切换不同的数据源?我们能不能在spring的框架下通过少量修改得到解决?是否有什么设计模式可以利用呢?
首先想到在spring的applicationContext中配置所有的dataSource。这些dataSource可能是各种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL等,也可能是不同的数据源:比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。然后sessionFactory根据客户的每次请求,将dataSource属性设置成不同的数据源,以到达切换数据源的目的。
spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
第六种:代理(Proxy)
为其他对象提供一种代理以控制对这个对象的访问。 ?从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。
spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。
第七种:观察者(Observer)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
第八种:策略(Strategy)
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
spring中在实例化对象的时候用到Strategy模式
在SimpleInstantiationStrategy中有如下代码说明了策略模式的使用情况:
第九种:模板方法(Template Method)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
Template Method模式一般是需要继承的。这里想要探讨另一种对Template Method的理解。spring中的JdbcTemplate,在用这个类时并不想去继承这个类,因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。这可能是Template Method不需要继承的另一种实现方式吧。
android 几种单例模式的写法
先不论单例模式的写法,有些方面是相同的,比如都需要将唯一的对象设置为static的,都需要将构造方法private化,代码如下:
public class MyInstance { private static MyInstance instance; private MyInstance(){}
}
第一种:最原始的单例模式,代码如下:
public static MyInstance getInstance(){ if(instance==null){ instance=new MyInstance();
} return instance;
}
多线程并发时,可能会出现重复new对象的情况,因此不提倡使用。
第二种:将整个方法块进行加锁,保证线程安全。
public static synchronized MyInstance getInstance(){ if(instance==null){ instance=new MyInstance();
} return instance;
}
这种代码下,每条线程都会依次进入方法块内部,虽然实现了单例,但是影响了运行效率,可以使用但是也不怎么提倡。
第三种:进一步优化的方法。
public static MyInstance getsInstance(){ synchronized (MyInstance.class){ if(instance==null){ instance=new MyInstance(); return instance;
}else{ return instance;
}
}
}
这种方式只是第二种方法的一种优化,但是优化有限。
(以下的几种方法比较推荐使用)
第四种:双层判断加锁,效率影响小且保证了线程安全。
public static MyInstance getsInstance() { if (instance == null) { synchronized (MyInstance.class) { if(instance==null){ instance=new MyInstance();
}
}
} return instance;
}
这种方法是对第二种和第三种方法的进一步优化,比较推荐使用。
第五种:内部类实现单例,不用线程锁来实现效率的提升。
public class MyInstance { private MyInstance() {
} public static MyInstance getInstance(){ return MyInstanceHolder.instance;
} private static class MyInstanceHolder{ private static MyInstance instance=new MyInstance();
}
}
在内部类中new对象,再将内部类的对象返回,这种方法是使用了java中class加载时互斥的原理来实现了线程的安全。不加线程锁也使得运行效率不会受到较大的影响。比较提倡。
JAVA单例模式的几种实现方法
JAVA
单例模式的几种实现方法
1.饿汉式单例类
package
pattern.singleton;
//
饿汉式单例类
.
在类初始化时,已经自行实例化
public
class
Singleton1
{
//
私有的默认构造子
private
Singleton1()
{}
//
已经自行实例化
private
static
final
Singleton1
single
=
new
Singleton1();
//
静态工厂方法
public
static
Singleton1
getInstance()
{
return
single;
}
}
2.
懒汉式单例类
package
pattern.singleton;
//
懒汉式单例类
.
在第一次调用的时候实例化
public
class
Singleton2
{
//
私有的默认构造子
private
Singleton2()
{}
//
注意,这里没有
final
private
static
Singleton2
single;
//
只实例化一次
static
{
single
=
new
Singleton2();
}
//
静态工厂方法
public
synchronized
static
Singleton2
getInstance()
{
if
(single
==
null
)
{
single
=
new
Singleton2();
}
return
single;
}
}
在上面给出懒汉式单例类实现里对静态工厂方法使用了同步化,以处理多线程环境。有些设计师在这里建议使用所谓的
"
双重检查成例
".
必须指出的是,
"
双重检查成例
"
不可以在
Java
语言中使用。不十分熟悉的读者,可以看看后面给出的小节。
同
样,由于构造子是私有的,因此,此类不能被继承。饿汉式单例类在自己被加载时就将自己实例化。即便加载器是静态的,在饿汉
式单例类被加载时仍会将自己实例化。单从资源利用效率角度来讲,这个比懒汉式单例类稍差些。从速度和反应时间角度来讲,
则
比懒汉式单例类稍好些。然而,懒汉式单例类在实例化时,必须处
理好在多个线程同时首次引用此类时的访问限制问题,特别是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源
初始化很有可能耗费时间。这意味着出现多线程同时首次引用此类的机率变得较大。
饿汉式单例类可以在
Java
语言内实现,
但不易在
C++
内实现,因为静态初始化在
C++
里没有固定的顺序,因而静态的
m_instance
变量的初始化与类的加载顺序没有保证,可能会出问题。这就是为什么
GoF
在提出单例类的概念时,举的例子是懒
汉式的。他们的书影响之大,以致
Java
语言中单例类的例子也大多是懒汉式的。实际上,本书认为饿汉式单例类更符合
Java
语
言本身的特点。
3.
登记式单例类
.
package
pattern.singleton;
import
java.util.HashMap;
import
java.util.Map;
//
登记式单例类
.
//
类似
Spring
里面的方法,将类名注册,下次从里面直接获取。
public
class
Singleton3
{
private
static
MapString,Singleton3
map
=
new
HashMapString,Singleton3();
static
{
Singleton3
single
=
new
Singleton3();
map.put(single.getClass().getName(),
single);
}
//
保护的默认构造子
protected
Singleton3(){}
//
静态工厂方法
,
返还此类惟一的实例
public
static
Singleton3
getInstance(String
name)
{
if
(name
==
null
)
{
name
=
Singleton3.
class
.getName();
System.out.println("name
==
null"+"---name="+name);
}
if
(map.get(name)
==
null
)
{
try
{
map.put(name,
(Singleton3)
Class.forName(name).newInstance());
}
catch
(InstantiationException
e)
{
e.printStackTrace();
}
catch
(IllegalAccessException
e)
{
e.printStackTrace();
}
catch
(ClassNotFoundException
e)
{
e.printStackTrace();
}
}
return
map.get(name);
}
//
一个示意性的商业方法
public
String
about()
{
return
"Hello,
I
am
RegSingleton.";
}
public
static
void
main(String[]
args)
{
Singleton3
single3
=
Singleton3.getInstance(
null
);
System.out.println(single3.about());
}
}
Java中单例模式有哪些实现方法
单例模式大致有五种写法,分别为懒汉,恶汉,静态内部类,枚举和双重校验锁。 1、懒汉写法,常用写法 class LazySingleton{ private static LazySingleton singleton; private LazySingleton(){ } public static LazySingleton getInstance(){ i...
如何写一个简单的单例模式?
简单的单例模式如下
[java]view plaincopyprint?
public class Singleton{
private static Singleton unique Instance=null;
private Singleton(){
//Exists only to defeat instantiation.
}
public static Singleton getInstance(){
if(unique Instance==null){
unique Instance=new Singleton();
}
return unique Instance;
}
//Other methods...
}
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。
每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。
总之,选择单例模式就是为了避免不一致状态,避免政出多头。
扩展资料
一、单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
二、单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
1.饿汉式单例类
[java]view plaincopyprint?
//饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1{
//私有的默认构造子
private Singleton1(){}
//已经自行实例化
private static final Singleton1 single=new Singleton1();
//静态工厂方法
public static Singleton1 getInstance(){
return single;
}
}
2.懒汉式单例类
[java]view plaincopyprint?
//懒汉式单例类.在第一次调用的时候实例化
public class Singleton2{
//私有的默认构造子
private Singleton2(){}
//注意,这里没有final
private static Singleton2 single=null;
//静态工厂方法
public synchronized static Singleton2 getInstance(){
if(single==null){
single=new Singleton2();
}
return single;
}
}
3.登记式单例类
[java]view plaincopyprint?
import java.util.HashMap;
import java.util.Map;
//登记式单例类.
//类似Spring里面的方法,将类名注册,下次从里面直接获取。
public class Singleton3{
private static MapString,Singleton3map=new HashMapString,Singleton3();
static{
Singleton3 single=new Singleton3();
map.put(single.getClass().getName(),single);
}
//保护的默认构造子
protected Singleton3(){}
//静态工厂方法,返还此类惟一的实例
public static Singleton3 getInstance(Stringname){
if(name==null){
name=Singleton3.class.getName();
System.out.println("name==null"+"---name="+name);
}
if(map.get(name)==null){
try{
map.put(name,(Singleton3)Class.forName(name).newInstance());
}catch(InstantiationExceptione){
e.printStackTrace();
}catch(IllegalAccessExceptione){
e.printStackTrace();
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
}
returnmap.get(name);
}
//一个示意性的商业方法
public String about(){
return"Hello,IamRegSingleton.";
}
public static void main(String[]args){
Singleton3 single3=Singleton3.getInstance(null);
System.out.println(single3.about());
}
}
参考资料:百度百科——java单例模式