设计模式-问题-工厂模式+单例模式

简单工厂

为什么一定要用工厂模式,能够举出使用简单工厂比我直接new Object()到底有哪些好处?

  • new Object可能还得去配置和组装对象的很多额外信息

    • 但是当前可能并不需要知道这么多额外信息,且不希望自己来组装,所以通过工厂来获取

    • 例如用户只想要一辆车,可能并不想知道车门的材料是什么厂商的,车轮是从哪里进口的

  • 其次如果说工厂里面生产的东西发生一些小的变更,只需要直接在工厂的地方修改就行了,如果用户自己来new的,那么所有用户自己创建的地方都需要修改,其实主要还是高内聚低耦合

工厂方法

为什么又有一个工厂方法,它解决了简单工厂的哪个问题?

  • 工厂方法主要用来解决简单工厂

    • 违背了开闭原则

    • 导致类非常庞大的问题

  • 我们通过工厂方法能够快速扩展工厂,而不会影响原有代码逻辑

image-20201230142015018

抽象工厂

举例说出抽象工厂的应用场景,我如果要增加一个答疑的产品应该怎么修改代码,你也可以基于老师的代码来完善这个功能

  • 如果代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建, 在这种情况下, 你可以使用抽象工厂。

  • 抽象工厂为你提供了一个接口, 可用于创建每个系列产品的对象。 只要代码通过该接口创建对象, 那么你就不会生成与应用程序已生成的产品类型不一致的产品。

  • 如果你有一个基于一组抽象方法的类, 且其主要功能因此变得不明确, 那么在这种情况下可以考虑使用抽象工厂模式。

  • 在设计良好的程序中, 每个类仅负责一件事。 如果一个类与多种类型产品交互, 就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。

  • 比如说女娲造人,需要有男人和女人,也需要有白种人,黑种人,黄种人,那么我们可以定义一个顶层接口Humanfactory然后FemaleFactoryMaleFactory都实现对应的HumanFactory的接口,然后对应的工厂创建对应的产品

  • image-20201230193534527
  • 增加答疑的产品的话需要新增一个答疑的接口,所有工厂都需要去修改补充对应的实现,所以改动会非常大

单例模式

仔细分析双重检查锁单例模式中,第一个if(instance ==null )和第二个 if(instance ==null)的作用是什么?为什么要加synchronize?不加volatile关键字会出现什么问题。

  • 第一个是为了避免反复进入锁,阻塞降低性能

  • 第二个是为了避免创建多个对象

  • synchronize是为了串行化

  • voldatile是为了a线程修改了变量之后其他线程都能够及时看到主要是为了解决可见性问题

静态懒汉式利用了JDK语法的什么特性

jdk的静态内部类只有在调用的时候才会初始化

怎么防止序列化破坏单例,最好去Debug一下源码,这样更有感觉而不是去记一个知识点。

重写readResolve方法,因为反序列化的时候会判断是否有这个方法,如果有的话会走这个方法来调用实例化这个对象

readResolveMethod = getInheritableMethod(
  cl, "readResolve", null, Object.class);

 Object invokeReadResolve(Object obj)
        throws IOException, UnsupportedOperationException
    {
        requireInitialized();
        if (readResolveMethod != null) {
            try {
                return readResolveMethod.invoke(obj, (Object[]) null);
            } catch (InvocationTargetException ex) {
                Throwable th = ex.getTargetException();
                if (th instanceof ObjectStreamException) {
                    throw (ObjectStreamException) th;
                } else {
                    throwMiscException(th);
                    throw new InternalError(th);  // never reached
                }
            } catch (IllegalAccessException ex) {
                // should not occur, as access checks have been suppressed
                throw new InternalError(ex);
            }
        } else {
            throw new UnsupportedOperationException();
        }
    }

Last updated