设计模式(经典类型)

设计模式是面向对象设计的实践经验总结,用于提高代码可复用性、可维护性。本文详细介绍了Java中的设计模式,包括创建型模式(单例、工厂、抽象工厂、构造者、原型模式)、结构型模式(适配器、桥接、装饰、组合、外观、享元、代理)和行为型模式(模板方法、观察者等),并阐述了OOP七大原则及其在设计模式中的应用。此外,还详细讲解了Java类加载机制,以及单例模式的多种实现方式。
摘要由CSDN通过智能技术生成

设计模式

设计模式是前辈们对代码开发经验的总结,是解决特定问题的一系列的套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

学习设计模式的意义

设计模式的本质是面向对象设计原则的实际应用,是对类的封装性、继承性和多态性以及类的关联关系的组合关系的充分理解。

正确使用设计模式具有一下优点:

  • 可以提高程序员的思维能力、编程能力和设计能力
  • 是程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期
  • 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强

设计模式的分类

  • 创建型模式:
    • 单例模式、工厂模式、抽象工厂模式、创造者模式、原型模式
  • 结构型模式:
    • 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
  • 行为型模式
    • 模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式

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(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值