开发中常用的设计模式,面试时问题解答 及 简单手写上 (单例模式 简单工厂模式 工厂模式)

面试中会被问到了解过什么设计模式吗,其实设计模式23种那么多,都了解一般水平的小伙伴做不到,想详细学习的可以看专门介绍设计模式的书籍,此篇文章主要介绍几种简单常用的,(单例、简单工厂、工厂)下篇将介绍(装饰、策略、观察者)[https://blog.csdn.net/liuguangxu1988/article/details/82055853]熟练描述,外加手写个小例子,代码实现,会加分不少。下面结合了网上的一些资料,部分仿照了刘望舒大神分享的例子。吃水不忘挖井人,大神的《Android进阶之光》推荐大家阅读购买。

一 单例模式

主要用于开发环境中的工具类(ToastUtil,SharepreferenceUtil等)简单的懒汉饿汉不写了,主流的两种写法及分析如下
第一种 双重检查写法

public class Singleton {
    private static volatile Singleton sInstance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (sInstance == null) {//第一次判空减少不必要的同步
            synchronized (Singleton.class) {
                if (sInstance == null) {//第二次判空,实例为空再创建对象
                    sInstance = new Singleton();
                }
            }
        }
        return sInstance;
    }
}

这时面试官基本会问volatile 这个关键字有什么作用

1保证线程修改的可见性
Java语言编写的程序,有时为了提高运行效率,编译器会自动对其优化,把经常访问的变量缓存起来,程序在读取这个变量时有可能直接从缓存(例如寄存器)中读取,而不会去内存中读取。当多线程编程时,变量的值可能因为别的线程改变了,而该缓存的值不会相应的改变,从而造成读取的值与实变量的值不一致。
volatile 被设计用来修饰不同线程访问和修改的变量。被volatile 类型定义的变量,系统每次用到他时都直接从对应的内存中提取,而不会利用缓存。这样所有线程在任何时候拿到的变量的值都是相同的。

2禁止指令重排序
在Java内存模型(JMM)中,并不限制处理器的指令顺序,说白了就是在不影响结果的情况下,顺序可能会被打乱。
在执行sInstance = new Singleton();这条命令语句时,JMM并不是一下就执行完毕的,即不是原子性,实质上这句命令分为三大部分:
1. 为对象分配内存
2. 执行构造方法语句,初始化实例对象
3. 把sInstance的引用指向分配的内存空间
在JMM中这三个步骤中的2和3不一定是顺序执行的,如果线程A执行的顺序为1、3、2,在第2步执行完毕的时候,恰好线程B执行第一次判空语句,则会直接返回sInstance,那么此时获取到的sInstance仅仅只是不为null,实质上没有初始化,这样的对象肯定是有问题的!
而volatile关键字的存在意义就是保证了执行命令不会被重排序,也就避免了这种异常情况的发生,所以这种获取单例的方法才是真正的安全可靠!

第二种 静态内部类

public class Singleton {
    private Singleton() {}
    private static class SingletonHolder {
        private static Singleton sInstance = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.sInstance;
    }
}

当外部类Singleton被加载时,其静态内部类SingeletonHolder不会被加载,所以它的成员变量sInstance是不会被初始化的,只有当调用Singleton.getInstance()方法时,才会加载SingeletonHolder并且初始化其成员变量,而类加载时是线程安全的,这样既保证了延迟加载,也保证了线程安全,同时也简化了代码量,一举三得!

二 简单(静态)工厂模式

简单(静态)工厂模式 和 工厂模式(基本会问下这两个的区别)
1简单工厂模式,又叫静态工厂模式,其实并不属于23中GOF之一,为了方便后文的工厂模式。
涉及到
Factory 工厂类 IProduct 抽象产品类 Product 具体产品类 举例如下
一个手机代工厂,可以生产华为手机,业务发展,还要生产小米、OPPO手机,这样一个单独的类来生产手机,用到简单工厂模式。
1抽象产品类 抽象手机,抽象开机方法

public abstract class Cellphone{
    public abstract void start();
}

2具体产品类 继承父类Cellphone,实现start方法

public class HuaweiPhone extends Cellphone{
    @Override
    public void start(){
        System.out.println("华为手机开机");
    }
}
public class MiPhone extends Cellphone{
    @Override
    public void start(){
        System.out.println("小米手机开机");
    }
}
public class OPPOPhone extends Cellphone{
    @Override
    public void start(){
        System.out.println("OPPO手机开机");
    }
}

3工厂类 提供静态方法createCellphone来生产手机

public class CellphoneFactory{
    public static Cellphone createCellphone(String type){
        Cellphone mCellphone = null;
        switch(type){
            case "Huawei":
                mCellphone  = new HuaweiPhone();
                break;
            case "Mi":
                mCellphone  = new MiPhone();
                break;
            case "OPPO":
                mCellphone  = new OPPOPhone();
                break;
        }
        return mCellphone;
    }
}

4客户端调用

public class createCellphone{
    public static void main(String[] args){
        CellphoneFactory.createCellphone("Mi").start();
    }
}

使用场景及优缺点
场景
*工厂类负责创建的对象比较少
*客户只需要知道传入工厂的参数,而无需关心创建对象的逻辑
优点:根据参数获得对应的实例,避免了直接实例化类,降低了耦合性。
缺点:可实例化的类型在编译期已被确定,如果增加新类型(生产VIVO手机),则要修改工厂,违反了开放封闭原则。当子类过多或子类层次过多时不适合使用。

三 工厂模式

涉及到
Factory 抽象工厂类 ConcreteFactory 具体工厂类
Product 抽象产品类 ConcreteProduct 具体产品类
简单实现
1创建抽象工厂

public abstract class CellphoneFactory{
    public abstract<T extends Cellphone> T createCellphone(Class<T> clz)
}

2具体工厂 继承抽象工厂,通过反射来创建手机

public class MyCellphoneFactory extends CellphoneFactory{
    @Override
    public <T extends Cellphone> T createCellphone(Class<T> clz){
        Cellphone mCellphone = null;
        String classname = clz.getName();
        try{
            mCellphone = (Cellphone)Class.forName(classname).newInstance();
        }catch(Excepion e){
            e.printStackTrace();
        }
        return (T) Cellphone;
    }
}

3客户端调用

public class Client{
    public static void main(String[] args){
        CellphoneFactory cellphoneFactory = new MyCellphoneFactory();
        HuaweiPhone huaweiPhone = cellphoneFactory.createCellphone(HuaweiPhone.class);
        huaweiPhone.sart();
        MiPhone miPhone = cellphoneFactory.createCellphone(MiPhone.class);
        miPhone.sart();
        OPPOPhone oppoPhone = cellphoneFactory.createCellphone(OPPOPhone.class);
        oppoPhone.start();
    }
}

简单工厂模式与工厂模式的对比
简单工厂模式:如果要增加产品,就需要在工厂类添加一个Case分支,违反了开放封闭原则,对修改也开放了。
工厂模式没有违反这个原则,如果要生产VIVO手机,无需修改工厂类,直接创建产品即可。

总结

单例 简单(静态)工厂 工厂模式属于创建型设计模式,还有(建造者,原型模式),这篇博客写的比较简单,在于给读者一个简单的思路,在回答问题上可以清晰,有条理,同时代码示例也非常简洁,在面试官让手写时也可写一下,码字不易点个赞吧,谢谢大家!

  • 15
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值