***首先设计模式的产生肯定是为了解决问题:***产生的原因:
由于用户需求的多变,客户需求,技术需求的 变化,我们原有的代码会被摧毁所以就出现了
新的需求—设计模式;
解决的问题以及办法
程序中代码的复用的问题;分析设计模式得从2个方面来分析,一个是抽象原理,一个是底层实现,通过分解和抽象来解决问题。
设计模式遵循的原则
(1)依赖倒置原则:高层模块不应该依赖底层模块,二者都应该依赖与抽象抽象不应该依赖与具体的依赖细节;稳定模块不应该依赖变化模块,我们应该提出抽象类;
(2)开放-封闭原则:对扩展开放,对更改封闭;
(3)单一职责原则一个类应该仅有一个引发它变化的原因,变化的方向隐含了类的多个责
(4)替换原则:Liskov替换原则 父类可以替换子类子类必须能够替换他们的基类 表达他们的方式
(5)接口隔离原则:不应该强迫客户程序依赖他们不用的原则接口应该小而完备;
(6)优先使用对象组合而不是类继承继承在某种程度上破坏了封装性,子类父类耦合度高
(7)封装变化点原则:使用封装来创建对象的分解层,让设计者可以在分界点
(8)针对接口编程而不是针对实现编程
设计模式划分:
创建形:对象创建的工作,
结构性:对对象结构的冲击
行为型:责任交互的划分的冲击范围划分
划分设计模式:
组件协作类
单一职责:
对象创建
对象性能
接口隔离
状态变化
数据结构
行为变化
领域问题
(1)对象性能 的2种设计模式
第一种 单例模式(Lazy懒汉模式)
实现原理:类的懒加载机制 对象不会直接被创建,只有当我们调用创建方法的时候,对象才会被创建;
第一步:声明 volatile一个 对象(保证对象有序性 和 可见性)
第二部:私有化构造 通过 private
第三步:提供全局唯一的 静态方法 返回一个对象,全局唯一的访问点;
第四步:通过synchronized 修饰保证 对象的
原子性 ,
package LazySingleton;
public class LazySingletonTest {
public static void main(String[] args) {
for(int a=0; a<2; a++){
new Thread(new Runnable() {
@Override
public void run() {
LazySingleton instance = LazySingleton.getInstance();
}
});
}
}
}
class LazySingleton{
//字节码层 的操作
/**
* 分配空间
* 初始化
* 引用赋值
* JIT 编译器 编译的时候防止发生指令重排所以就需要
* 多线程下 线程A给instance赋值完毕后,线程B
*/
private volatile static LazySingleton instance;
//私有化构造
private LazySingleton(){}
//提供一个全局唯一的访问点
public static LazySingleton getInstance(){
synchronized(LazySingleton.class){
if(instance==null){
instance=new LazySingleton();
System.out.println(instance);
}
}
return instance;
}
}
单例模式二 hungery 饿汉模式 原理是使用了虚拟机的类加载机制(被static修饰的代码块只会被初始化一次)
第一步 直接创建一个对象 静态的
第二部:私有化 构造
第三步:提供一个全局唯一的访问点
当然上述的步骤不一定可以保证类的singleton
安全,我们仍然可以通过 反射以及序列化来
对我们需要的对象就进行构建和 修改
解决办法:在私有化构造加入逻辑判断,
序列化的解决办法,在 @Serializable注解种
也提供了对应的办法
package HungrySingleton;
public class HungrySungletonTest {
public static void main(String[] args) {
//调用类的实例化的方法时候,会先去验证这个类有没有被加载
//父类有没有被加载 没有的话先去加载父类,也就是触发初始化的操作
HungrySingleton instance = HungrySingleton.getInstance();
HungrySingleton instance1 = HungrySingleton.getInstance();
System.out.println(instance==instance1);
}
}
//饿汉模式:类加载的 初始化阶段就完成了实例的初始化,本质上就是借助JVM的机制 保证了实例的唯一性
//javaC进行编译-----jvm类加载器加载字节码文件------初始化(连接:1验证,2准备(给静态成员变量赋默认值)3解析(把常量池中的
// 符号引用办成直接引用,对应到我们方法区的内存空间))
//只有在整整使用对应的类时候,才会出啊发初始化 如(main函数所在的类用反射访问类信息,直接使用new)
class HungrySingleton{
//静态变量在JVM加载类的时候就会被初始化,只能被初始化一次
private static volatile HungrySingleton instance = new HungrySingleton();
//私有化构造
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
第二种 享元模式