Java 23种设计模式

参考:Java设计模式(疯狂Java联盟版).chm

设计模式:共有23种,每个设计模式都是用来解决某个问题的固定步骤【固定解决方案】

在这里插入图片描述

一、单例模式

单例模式:根据一个类,不管实例化出多少对象,都为同一个对象
解决一个类在内存中只存在一个对象,想要保证对象的唯一

在这里插入图片描述

步骤:

  1. 为了避免其他程序过多的建立该类对象,禁止其他程序建立该类对象【构造器私有化
  2. 为了其他程序可以访问该类对象,在本类中自定义一个对象【类中创建一个私有的本类对象
  3. 方便其他程序对自定义类的对象的访问,对外提供一些访问方式【定义静态方法获取该对象

单例模式分为:
饿汉模式:顾名思义,他是一个懒汉,他不愿意动弹。什么时候需要吃饭了,他就什么时候开始想办法搞点食物。
即懒汉式一开始不会实例化,什么时候用就什么时候new,才进行实例化。

懒汉模式:
顾名思义,他是一个饿汉,他很勤快就怕自己饿着。他总是先把食物准备好,什么时候需要吃了,他随时拿来吃,不需要临时去搞食物。
即饿汉式在一开始类加载的时候就已经实例化,并且创建单例对象,以后只管用即可。

代码案例

package cn.com.example8;

public class SingleClass {

    

}

// 饿汉模式
class SingleClass0{
    
    // 实例化私有化本类对象
    private static SingleClass0 SingleClass0 = new SingleClass0();

    // 私有化构造器
    private SingleClass0(){}

    // 定义静态方法用于获取该对象
    public static SingleClass0 getSingleClass0(){

        return SingleClass0;
    }
}


// 懒汉模式
class SingleClass1{
    
    // 声明一个该类类型的变量
    private static SingleClass1 singleClass1 = null;
    
    // 私有化构造器
    private SingleClass1(){}
    
    // 定义静态方法用于获取该对象
    public static SingleClass1 getSingleClass1(){
        // 判断singleClass1的值  null:实例化对象   !null:返回
        if(singleClass1 == null){
            singleClass1 = new SingleClass1();
        }
        
        return singleClass1;
    }
    
}

二、工厂模式

工厂模式:用工厂方法代替new操作的一种模式,也就是说工厂模式就相当于创建实例对象的new【不需要new对象,而是获取对象】,这样会给系统带来更大的可扩展性和降低耦合度

1、简单工厂模式

简单工厂模式不属于23种设计模式,相当于一种编程习惯

简单工厂模式包含如下三种角色:

  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能
  • 具体产品:实现或继承抽象产品的子类
  • 具体工厂:提供了创建产品的方法,使用者通过该方法来获取产品

在这里插入图片描述

代码案例

package cn.com.example8;
// 简单工厂模式
// 具体工厂
public class EasyFactory {
    
    // 获取Coffee对象 -- 方法一
    public RuiXingCoffee getRuiXingCoffee(){
        return new RuiXingCoffee();
    }
    
    public XingBaKeCoffee getXingBaKeCoffee(){
        return new XingBaKeCoffee();
    }


    // 获取Coffee对象 -- 方法二
    public Coffee getCoffee(String type){

        Coffee coffee = null;
        if("ruixing".equals(type)){
            coffee = new RuiXingCoffee();
        }else if("xingbake".equals(type)){
            coffee = new XingBaKeCoffee();
        }
        
        return coffee;
    }


}


// 抽象产品-抽象类
abstract class Coffee{

}


// 具体产品-子类
class RuiXingCoffee extends Coffee{

}

class XingBaKeCoffee extends Coffee{

}

缺陷:
1、工厂处理创建对象的细节,一旦有了工厂,后期如果需要对象直接从工厂中获取即可,这样也就解除了和实现类的耦合【使用方-实现类】,但同时产生了新的耦合【工厂-实现类】。
2、后期如果在添加新的类,就必须更改工厂类的代码,违反了开闭原则。

2、静态工厂模式

静态工厂模式:在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的,这个就是静态工厂模式,它也不是23种设计模式中的。

在这里插入图片描述

代码案例

package cn.com.example8;
// 简单工厂模式
// 具体工厂
public class EasyFactory {
    
    // 获取Coffee对象 -- 方法一
    public static RuiXingCoffee getRuiXingCoffee(){
        return new RuiXingCoffee();
    }
    
    public static XingBaKeCoffee getXingBaKeCoffee(){
        return new XingBaKeCoffee();
    }


    // 获取Coffee对象 -- 方法二
    public static Coffee getCoffee(String type){

        Coffee coffee = null;
        if("ruixing".equals(type)){
            coffee = new RuiXingCoffee();
        }else if("xingbake".equals(type)){
            coffee = new XingBaKeCoffee();
        }
        
        return coffee;
    }


}


// 抽象产品-抽象类
abstract class Coffee{

}


// 具体产品-子类
class RuiXingCoffee extends Coffee{

}

class XingBaKeCoffee extends Coffee{

}

3、工厂方法模式

工厂方法模式:是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入达到解耦、复用和方便后期维护拓展的目的,它的核心结构有四个角色,分别是抽象工厂、具体工厂、抽象产品和具体产品

四种角色:

  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能
  • 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它和具体工厂之间—对应
  • 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建
  • 抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品

在这里插入图片描述

代码案例

/**
* 抽象工厂
**/
public interface CoffeeFactory {
    Coffee createCoffee();
}

/**
* 具体工厂
* 
* 抽象产品为coffee,具体产品为LatteCoffee和AmericanCoffee
* 这种工厂模式可以通过不同的具体工厂创建出不同的具体产品
**/
public class LatteCoffeeFactory implements CoffeeFactory {
    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}

public class AmericanCoffeeFactory implements CoffeeFactory {
    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}

优点:在获取对象时只需要知道具体工厂的名称就可以得到对应的对象,无须知道具体创建过程,在系统增加新的类时只需要添加对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则

缺点:每增加一个类就要增加一个对应的具体工厂类,增加了系统的复杂度

4、模式扩展【简单工厂+配置文件解除耦合】

可以通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合,在工厂类中加载配置文件中的全类名,并创建对象进行存储,客户端如果需要对象,直接获取即可

在这里插入图片描述

4.1、创建配置文件

ruixing=cn.com.example7.RuiXingCoffee
XingBaKe=cn.com.example7.XingBaKeCoffee

代码案例

public class CoffeeFactory {
    private static Map<String,Coffee> map = new HashMap();
    // 加载配置文件
    static {
        Properties p = new Properties();
        InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            p.load(is);
            // 遍历Properties集合对象
            Set<Object> keys = p.keySet();
            for (Object key : keys) {
                // 根据键获取值(全类名)
                String className = p.getProperty((String) key);
                // 获取Class对象
                Class clazz = Class.forName(className);
                // 实例化对象
                Coffee obj = (Coffee) clazz.newInstance();
                // 将对象以键值对的形式存入map
                map.put((String)key,obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

  /**
  * 获取对象时直接根据配置文件中的key获取对应的对象
  **/
    public static Coffee createCoffee(String name) {
        return map.get(name);
    }
}

三、模板模式

模板模式:在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。
模板模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤,这里的算法,我们可以理解为广义上的业务逻辑,并不特指数据结构和算法中的算法,这里的算法骨架就是模板,包含算法骨架的方法就是模板方法

在这里插入图片描述

检测程序运行时间-代码案例:RunCode.java

package cn.com.example8;

public abstract class RunCode {

    // 模板方法
    public final void getRunTime(){

        // 获取开始时间
        long start = System.currentTimeMillis();

        // 算法骨架
        code();

        // 获取结束时间
        long end = System.currentTimeMillis();

        System.out.println("程序运行时间:"+(end - start));

    }



    // 算法骨架
    abstract void code();

}

TestRunCode.java

package cn.com.example8;

public class TestRunCode extends RunCode{

    @Override
    void code() {
        System.out.println("这是具体算法程序");
    }


    public static void main(String[] args) {

        new TestRunCode().getRunTime();

    }

}

四、代理模式

1、代理模式概述

代理模式:为其他对象提供一种代理用于控制对这个对象的访问。
在某些场景下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用

代理模式三个角色:

  1. 抽象角色:通过接口或抽象类声明真实角色实现的业务方法
  2. 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作
  3. 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用

在这里插入图片描述

2、代理模式入门程序

2.1、抽象角色:接口

package cn.com.example8;

// 抽象角色
public interface Target {

    void handlerMessage();

}

2.2、真实角色:实现类

package cn.com.example8;

// 真实角色
public class TargetImpl implements Target{

    @Override
    public void handlerMessage() {

        System.out.println("这是真实角色的handlerMessage方法");

    }

}

2.3、代理角色:实现类

package cn.com.example8;

// 代理角色
public class TargetProxy implements Target{

    // Target属性
    public Target target = null;

    public TargetProxy(){}

    public TargetProxy(Target target){
        this.target = target;
    }

    @Override
    public void handlerMessage() {

        // 调用其他操作
        // 权限校验

        target.handlerMessage();

        // 调用其他操作
        // 日志记录
        // 性能监控

    }
}

2.4、测试类

package cn.com.example8;

// 测试类
public class TestTargetProxy {

    public static void main(String[] args) {


        // 实例化真实角色对象
        TargetImpl targetImpl = new TargetImpl();

        // 实例化代理角色对象  并赋值
        TargetProxy targetProxy = new TargetProxy(targetImpl);

        // 调用方法
        targetProxy.handlerMessage(); // 其实调用的是代理中handlerMessage方法中TargetImpl中的handlerMessage方法

    }
}

3、代理模式分类

3.1、静态代理

是由程序员创建或工具生成代理类的源码,在编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。【代理模式入门程序就是静态代理】

3.2、动态代理

是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

优点

  1. 职责清晰
    • 真实的角色就是实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰
  2. 中介作用
    • 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用
  3. 高扩展性

Java动态代理底层实现

在JDK的API中提供了java.lang.reflect.Proxy,它可以帮助我们完成动态代理的创建。

注意:在Java中使用Proxy来完成动态代理创建,它只能为目标实现了接口的类创建代理。【动态代理是在内存中直接生成了代理对象】

在这里插入图片描述

我们可以使用Proxy的静态方法newProxyInstance完成代理对象的创建

在这里插入图片描述

代码案例

package cn.com.example8;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Java动态代理
 */
public class TestProxy {

    public void testProxy(){

        // 实例化目标对象
        TargetImpl target = new TargetImpl();

        // 通过Proxy类调用静态方法生成目标对象对应的代理对象
        Target targetProxy = (Target) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return method.invoke(target, args);
            }
        });

        targetProxy.handlerMessage();

    }

}

newProxyInstance参数详解

  1. ClassLoader
    • 目标类的类加载器
    • 可以通过反射机制获取
    • 目标对象.getClass().getClassLoader()
  2. Class[] interfaces
    • 目标类实现的接口
    • 可以通过反射机制获取
    • 目标对象.getClass().getInterfaces()
    • 以上JVM帮我们创建代理对象
  3. InvocationHandler
    • 用于监听代理对象程序的调用
    • 底层:观察者模式
    • 如果监听到了代理对象要调用方法时,那么InvocationHandler帮我们调用目标方法

InvocationHandler详解

是一个接口,用于监听代理对象程序的调用
底层:观察者模式
如果监听到了代理对象要调用方法时,那么InvocationHandler帮我们调用目标方法
该接口中有一个invoke方法,当代理对象调用了该方法时,InvocationHandler就会调用invoke方法

invoke方法参数

在这里插入图片描述

  1. Proxy
    • 代理对象
  2. Method
    • 目标对象中的目标方法
  3. Args
    • 目标方法的参数

开发中我们常用于性能监控、日志记录、权限校验等功能。

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云游墨客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值