设计模式
设计模式是前辈们对代码开发经验的总结,是解决特定问题的一系列的套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
学习设计模式的意义
设计模式的本质是面向对象设计原则的实际应用,是对类的封装性、继承性和多态性以及类的关联关系的组合关系的充分理解。
正确使用设计模式具有一下优点:
- 可以提高程序员的思维能力、编程能力和设计能力
- 是程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期
- 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强
设计模式的分类
- 创建型模式:
- 单例模式、工厂模式、抽象工厂模式、创造者模式、原型模式
- 结构型模式:
- 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
- 行为型模式
- 模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式
OOP七大原则
- 开闭原则: 对扩展开放,对修改关闭
- 里氏替换原则: 继承必须确保超类所拥有的性质在子类中仍然成立
- 依赖导致原则: 要面向接口编程,不要面向实现编程
- 单一职责原则: 控制类的粒度大小、将对象解耦、提高其内聚性
- 接口隔离原则: 要为各个类建立他们需要的专用接口
- 迪米特法则: 只与你的直接朋友交谈,不跟”陌生人”说话
- 合成复用原则: 尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
1.Java类加载机制
类加载的时机
- 隐式加载 new 创建类的实例,
- 显式加载:loaderClass,forName等
- 访问类的静态变量,或者为静态变量赋值
- 调用类的静态方法
- 使用反射方式创建某个类或者接口对象的Class对象。
- 初始化某个类的子类
- 直接使用
java.exe
命令来运行某个主类
类加载的过程
加载–》验证–》准备–》解析–》初始化
加载
类加载过程的一个阶段,ClassLoader通过一个类的完全限定名查找此类字节码文件,并利用字节码文件创建一个class对象。
验证
目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身的安全,主要包括四种验证:文件格式的验证,元数据的验证,字节码验证,符号引用验证。
准备
为类变量(static修饰的字段变量)分配内存并且设置该类变量的初始值,(如static int i = 5 这里只是将 i 赋值为0,在初始化的阶段再把 i 赋值为5),这里不包含final修饰的static ,因为final在编译的时候就已经分配了。这里不会为实例变量分配初始化,类变量会分配在方法区中,实例变量会随着对象分配到Java堆中
解析
这里主要的任务是把常量池中的符号引用替换成直接引用
初始化
这里是类记载的最后阶段,如果该类具有父类就进行对父类进行初始化,执行其静态初始化器(静态代码块)和静态初始化成员变量。(前面已经对static 初始化了默认值,这里我们对它进行赋值,成员变量也将被初始化)
2.单例模式
特点:保证一个类只有一个实例,并且提供一个全局访问点
2.1懒汉模式
懒汉模式:延迟加载, 只有在真正使用的时候,才开始实例化。
问题:
- 线程不安全
- 指令重排
package com.wdzl;
/**
* 懒汉模式
*/
public class LazySingleton {
private LazySingleton() {
}
private volatile static LazySingleton instance;
/**
* 双重锁
*
* @return
*/
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
// 字节码层,创建对象
// JIT , CPU 有可能对如下指令进行重排序
// 1 .分配空间
// 2 .初始化
// 3 .引用赋值
}
}
}
return instance;
}
}
2.2饿汉模式
饿汉模式:类加载的 初始化阶段就完成了 实例的初始化 。
本质上就是借助于jvm 类加载机制,保证实例的唯一性(初始化过程只会执行一次)及线程安 全(JVM以同步的形式来完成类加载的整个过程)。
package com.wdzl;
/**
* 饿汉模式
*/
public class HungrySingleton {
private HungrySingleton(){
}
private static HungrySingleton instance=new HungrySingleton();
public static HungrySingleton getInstance(){
return instance;
}
}
2.3静态内部类
1).本质上是利用类的加载机制来保证线程安全
2).只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一 种形式。
package com.wdzl;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class InnerClassSingleton {
private InnerClassSingleton(){
}
private static class InnerClassHolder{
private static InnerClassSingleton instance=new InnerClassSingleton();
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//反射创建对象
Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
InnerClassSingleton innerClassSingleton = declaredConstructor.newInstance();
//调用方法创建对象
InnerClassSingleton instance = InnerClassSingleton.getInstance();
System.out.println(innerClassSingleton==instance);
}
}
静态内部类防止反射破坏
private InnerClassSingleton(){
if (InnerClassHolder.instance!=null){
throw new RuntimeException("单例不允许有多个实例");
}
}
2.4枚举类型
1)天然不支持反射创建对应的实例,且有自己的反序列化机制
2)利用类加载机制保证线程安全
可以发现是因为EnumSingleton.class.getDeclaredConstructors()获取所有构造器,会发现并没有我们所设置的无参构造器,只有一个参数为(String.class,int.class)构造器,然后看下Enum源码就明白,这两个参数是name和ordial两个属性:
package com.wdzl;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public enum EnumSingleton {
INSTANCE;
public void print(){
System.out.println(this.hashCode());
}
}
class Demo{
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumSingleton instance = EnumSingleton.INSTANCE;
EnumSingleton instance2 = EnumSingleton.INSTANCE;
instance.print();
instance2.print();
System.out.println(instance==instance2);
Constructor<EnumSingleton> declaredConstructor = EnumSingleton.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingleton enumSingleton = declaredConstructor.newInstance();
}
}
3.工厂模式
核心本质:
- 实例化对象不适用new, 用工厂方法代替
- 将选择实现类,创建对象统一管理和控制,从而将调用者跟我们的实现类解耦
三种模式:
- 简单工厂模式
- 用来生产同一等级结构中的任何产品(对于增加新的产品,需要扩展已有代码)
- 工厂方法模式
- 用来生产同一等级结构中的固定产品(支持增加任意产品)
- 抽象工厂模式
- 围绕一个超级工厂创建其他工厂,该超级工厂又被称为其他工厂的工厂
3.1简单工厂模式
1.定义一个接口
package com.wdzl.fatory.simple;
public interface Car {
void getName();
}
2.接口实现类
public class Tesl implements Car {
@Override
public void getName() {
System.out.println("特斯拉。。。");
}
}
public class WuLing implements Car{
@Override
public void getName() {
System.out.println("五菱宏光。。。");
}
}
public class R8 implements Car{
@Override
public void getName() {
System.out.println("奥迪R8.。。。");
}
}
3.简单工厂
package com.wdzl.fatory.simple;
//静态工厂模式
public class CarFactory {
// 方法一 违反了开闭原则
public static Car getCar(String car){
if ("五菱宏光".equals(car)){
return new WuLing();
}else if ("特斯拉".equals(car)){
return new Tesl();
}else{
return new Car() {
@Override
public void getName() {
System.out.println("没这车");
}
};
}
}
// 方法二
public static Car getWuLing(){
return new WuLing();
}
public static Car getTesl(){
return new Tesl();
}
public Car getR8(){
return new R8();
}
}
4.消费者(输出)
package com.wdzl.fatory.simple;
public class Consumer {
public static void main(String[] args) {
//正常方法
Car car=new WuLing();
Car car2=new Tesl();
car.getName();
car2.getName();
//使用工厂创建 方法一
Car wl=CarFactory.getCar("五菱宏光");
wl.getName();
Car tl=CarFactory.getCar("特斯拉");
tl.getName();
//方法二
Car wl2=CarFactory.getWuLing();
wl2.getName();
Car tl2=CarFactory.getTesl();
tl2.getName();
/**
* 不使用静态方法
*/
CarFactory carFactory = new CarFactory();
Car r8 = carFactory.getR8();
r8.getName();
}
}
3.2工厂方法模式
接口与接口的实现类与简单工厂模式定义相同
1.创建工厂方法
public interface CarFactory {
Car getCar();
}
public class TeslFactory implements CarFactory{
@Override
public Car getCar() {
return new Tesl();
}
}
public class R8Factory implements CarFactory{
@Override
public Car getCar() {
return new R8();
}
}
public class WuLingFactory implements CarFactory{
@Override
public Car getCar() {
return new WuLing();
}
}
2.输出
package com.wdzl.fatory.method;public class Consumer {
public static void main(String[] args) {
Car car=new WuLingFactory().getCar(); Car car2=new TeslFactory().getCar(); car.getName(