面试——设计模式--单例模式、工厂模式
·
1.单例模式


- 饿汉单例模式和懒汉单例模式构造方法都是私有的,因而是不能被继承的
1.懒汉式
双重检验实现
-
是否 Lazy 初始化:是
-
是否多线程安全:是
-
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。getInstance() 的性能对应用程序很关键。
1.为什么使用volitale关键字?
- 禁止指令重排。
因为singleton = new Singleton()这句话分为3步:- 1.为singleton分配内存空间;
- 2.初始化singleton;
- 3.将singleton指向分配的空间。
单线程下不会出问题。多线程下,如果指令重排,顺序变为1-3-2.会出现如下情况
2.为什么2次校验singleton?
- 第1次校验是为了效率。因为单例模式只需要1次创建实例,所以当创建1个实例之后,再次调用getInstance()方法,就不会进入synchronized同步代码块,不用再竞争锁。直接返回实例即可。
- 第2次校验是为了防止二次创建实例。假设:线程t1由于第1次判断为真,准备继续执行,t2线程却抢占了资源,也通过了第1次校验,进入了同步代码块,也通过了第2次校验,然后调用了getInstance()方法,创建了实例。等t2线程完成任务,t1会继续向下执行,再创建1个实例。所以会导致创建多个实例的情况发生。加上第2次校验,就可以完全避免此问题。
public class Singleton {
1.volatile关键字,禁止指令重排
private static volatile Singleton singleton = null;
2.只能内部调用,所以不是public
2.构造方法私有,所以不能被继承
private Singleton(){
}
public static Singleton getInstance(){
1.第一次校验singleton是否为空
if (singleton==null){
synchronized (Singleton.class){
2.第2次校验singleton是否为空
if (singleton==null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
2.饿汉式
- 是否多线程安全:是
- 描述:这种方式比较常用,但容易产生垃圾对象。
- 优点:没有加锁,执行效率会提高。
- 缺点:类加载时就初始化,浪费内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
public class Singleton {
1.静态方法加载
private static Singleton instance = new Singleton();
2.构造方法私有,所以不能被继承
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
2.工厂模式
-
优点:
- 1、一个调用者想创建一个对象,只要知道其名称就可以了。
- 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
- 3、屏蔽产品的具体实现,调用者只关心产品的接口。
-
缺点:
- 1.每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
-
实现:
创建一个 Phone 接口和实现 Phone 接口的实体类。下一步是定义工厂类 ShapeFactory。这样主程序的调用只涉及shapeFactory而创建对象的接口,让其子类自己决定实例化哪一种产品,工厂模式使其创建过程延迟到子类进行。
1.创建产品的接口、抽象类
abstract class Product {
public abstract String getProductName();
}
2.实现接口
class Telephone extends Product{
@Override
public String getProductName() {
return "TelePhone";
}
}
2.2再次实现接口
class Personalcomputer extends Product{
@Override
public String getProductName() {
return "Personalcomputer";
}
}
3.创建工厂类
class Facotry {
public static final String TELEPHONE = "telephone";
public static final String PersonalCom = "Personalcomputer";
1.静态方法可以直接调用,不必再new对象
public static Product produceProduct(String tagName){
Product product = null;
if(tagName.equals(TELEPHONE)){
product = new Telephone();
}else if (tagName.equals(PersonalCom)){
product = new Personalcomputer();
}
else{
return null;
}
return product;
}
}
4.测试工厂类
public class Test {
public static void main(String[] args) {
Product product1 = null;
Product product2 = null;
1.按名称,获得对象
product1 = Facotry.produceProduct(Facotry.TELEPHONE);
product2 = Facotry.produceProduct("Personalcomputer");
System.out.println("产品1名称:"+product1.getProductName());
System.out.println("产品2名称:"+product2.getProductName());
}
}
更多推荐

所有评论(0)