一 什么是设计模式?
通俗来说,设计模式就是牛人总结的解决某个问题的方案,这套方案被大多数人熟知和认可。
设计模式大致分为三种:
结构型
过滤器模式 组合模式 装饰器模式 外观模式 享元模式,代理模式
创建型
单例模式 工厂模式 抽象工厂模式 建造者模式 原型模式
行为型
责任链模式 命令模式 解释器模式 迭代器模式 中介者模式 备忘录模式 观察者模式 状态模式 空对象模式 策略模式 模板模式 访问者模式
说起设计模式,就不得不说起设计模式的六大设计原则
一 单一职责原则(Single Responsibility Principle - SRP)
一个类,只有一个引起它变化的原因。应该只有一个职责。
如果一个类承担的职责过多,就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而如果想要避免这种现象的发生,就要尽可能的遵守单一职责原则。此原则的核心就是解耦和增强内聚性。
二 开闭原则(Open-Closed Principle - OCP)
一个软件实体应当对扩展开放,对修改关闭。也就是说设计一个模块的时候,应当使这个模块在不被修改的前提下扩展。
三 里氏代换原则(Liskov Substitution Principle,或者LSP)
任何基类可以出现的地方,子类一定可以出现(对实现抽象化的具体步骤的规范)
四 迪米特法则(Law of Demeter,或者LoD)、
一个软件实体应当与尽可能少的实体发生相互作用(修改尽可能少的设计其他模块)
五 接口隔离原则(Interface Segregation Principle,或者ISP)
应为客户端提供尽可能少的单独的接口,而不要提供大的总接口(限制通信的宽度和深度)
六 依赖倒转原则(Dependency Inversion Principle,或者DIP)
依赖于抽象,不依赖于实现
此外也有其他设计原则,这里就不再详细叙述了,如 :
组合/聚合复用原则(Composition/Aggregation Principle,或者CARP)
二 单例设计模式(Singleton Pattern)
在程序的运行过程中,只有一个实例的存在(如:我们手机中只有一份联系人信息,而许多应用都需要读取这份信息,联系人信息就可以设计为单例)
1)饿汉单例模式
public class Singleton {
//1)构造方法私有化
private Singleton(){};
//2)定义一个私有的静态本类对象
private static Singleton obj=new Singleton();
//3)提供一个公共的静态方法,返回这个本类对象
public static Singleton getInstance(){
return obj;
}
}
优点
1.线程安全
2.在类加载的同时已经创建好一个静态对象,调用时反应速度快
缺点
资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化
2)懒汉单例模式
public class Singleton2 {
//1)构造方法私有化
private Singleton2(){};
//2)定义私有的静态的本类对象,不初始化
private static Singleton2 obj;
//3)提供一个公共的静态方法,返回这个本类对象(饿汉单例模式在多线程情况下可能存在线程安全问题,因此需要加synchronized关键字)
public static synchronized Singleton2 getInstance(){
if(obj==null){
obj=new Singleton2();
}
return obj;
}
}
优点:
避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。
缺点:
懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。
测试代码
public class Demo {
public static void main(String[] args) {
Singleton obj1=Singleton.getInstance();
Singleton obj2=Singleton.getInstance();
System.out.println(obj1);
System.out.println(obj2);
}
}
图解:
程序运行时,把Demo和Singleton的字节码文件加载到内存中,在Singleton类中有一个静态变量,类加载内存时在方法区的静态变量区中给obj这个变量分配空间,new运算会在堆中分配存储空间(如:0x1234),我们无论调用多少次getInstance()静态方法,返回的都是obj,因此都指向同一块堆内存。
通过单例设计模式,可以在多个类中共享数据。在某些情况下,利用单例可以节省资源,避免频繁的创建对象。