一:设计者模式六大原则和单例模式

设计者模式六大原则:

1.单一原则。描述的意思是每个类都只负责单一的功能,切不可太多业务,导致重复代码,并且一个类应当尽量的把一个功能做到极致。

2. 里氏替换原则:意思是一个子类应该可以替换掉父类并且可以正常工作。通俗的讲师尽量不要重写父类的方法,最好用接口的方式。

3.接口隔离原则:接口最小化原则,强调的是一个接口拥有的行为应该尽可能的小。即通用性,比如定义一个手机接口,只能定义所有手机都具有的特性。并且不能有事先方法。

4.依赖倒置原则:这个原则描述的是高层模块不该依赖于低层模块,二者都应该依赖于抽象,抽象不应该依赖于细节,细节应该依赖于抽象。

5. 迪米特原则:也称最小知道原则,即一个类应该尽量不要知道其他类太多的东西,不要和陌生的类有太多接触。(如果一个类知道或者说是依赖于另外一个类太多细节,这样会导致耦合度过高,应该将细节全部高内聚于类的内部)

6. 开-闭原则:一句话,对修改关闭,对扩展开放。

总体来说设计模式分为三大类
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

单例模式详解:

实例化类的时候,在应用中如果有两个或者两个以上的实例会引起错误,又或者我换句话说,就是这些类,在整个应用中,同一时刻,有且只能有一种状态的叫做单例

一般实践当中,有很多应用级别的资源会被做成单例,比如配置文件信息,逻辑上来讲,整个应用有且只能在同在时间有一个,当然如果你有多个,这可能并不会引起程序级别错误,这里指的错误特指异常或者ERROR。但是当我们试图改变配置文件的时候,问题就出来了。

最原始的单例模式的构造方式:

1.静态实例,带有static关键字的属性在每一个类中都是唯一的。

2.限制客户端随意创造实例,即私有化构造方法,此为保证单例的最重要的一步。

3.给一个公共的获取实例的静态方法,注意,是静态的方法,因为这个方法是在我们未获取到实例的时候就要提供给客户端调用的,所以如果是非静态的话,那就变成一个矛盾体了,因为非静态的方法必须要拥有实例才可以调用。

4.判断只有持有的静态实例为null时才调用构造方法创造一个实例,否则就直接返回。

 

  首先要明白在JVM创建新的对象时,主要要经过三步。

 1.分配内存

2.初始化构造器

 3.将对象指向分配的内存的地址

 所以我们在语言级别无法完全避免错误的发生,我们只有将该任务交给JVM,所以有一种比较标准的单例模式。如下所示。

  好了,进行到这里,单例模式算是已经完成了。最终的产物就是如上述的形式。上述形式保证了以下几点。

  1.Singleton最多只有一个实例,在不考虑反射强行突破访问限制的情况下。

  2.保证了并发访问的情况下,不会发生由于并发而产生多个实例。

3.保证了并发访问的情况下,不会由于初始化动作未完全完成而造成使用了尚未正确初始化的实例。

 以下为不太常用的方式,这里给出来只是给各位参考,不建议使用下述方式。

  第一种,就是俗称的饿汉式加载

public class Singleton {
    private static Singleton singleton = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return singleton;
    }
}

上述方式与我们最后一种给出的方式类似,只不过没有经过内部类处理,这种方式最主要的缺点就是一旦我访问了Singleton的任何其他的静态域,就会造成实例的初始化,而事实是可能我们从始至终就没有使用这个实例,造成内存的浪费。

不过在有些时候,直接初始化单例的实例也无伤大雅,对项目几乎没什么影响,比如我们在应用启动时就需要加载的配置文件等,就可以采取这种方式去保证单例。

 第二种 懒汉式单例模式在第一次调用 getInstance() 时才创建实例。这种实现需要考虑线程安全问题。

public class LazySingleton {
    // 持有一个静态变量来存储单例实例
    private static LazySingleton instance;

    // 私有构造函数,防止外部实例化
    private LazySingleton() {}

    // 提供全局访问点,并确保线程安全
    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

 这样也不会出现实例化发生一半的情况,因为加入了volatile关键字,就等于禁止了JVM自动的指令重排序优化,并且强行保证线程中对变量所做的任何写入操作对其他线程都是即时可见的。这里没有篇幅去介绍volatile以及JVM中变量访问时所做的具体动作,总之volatile会强行将对该变量的所有读和取操作绑定成一个不可拆分的动作。如果读者有兴趣的话,可以自行去找一些资料看一下相关内容。

不过值得注意的是,volatile关键字是在JDK1.5以及1.5之后才被给予了意义,所以这种方式要在JDK1.5以及1.5之后才可以使用,但仍然还是不推荐这种方式,一是因为代码相对复杂,二是因为由于JDK版本的限制有时候会有诸多不便。

 

posted @ 2019-06-24 14:13  威兰达  阅读(1062)  评论(0编辑  收藏  举报