设计模式&动态代理

时间:2024-05-01 15:35:58

什么是设计模式?

  • 一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式

    设计模式有20多种,对应20多种软件开发中会遇到的问题。

关于设计模式的学习,主要学什么?

  1. 解决什么问题
  2. 如何写

设计模式:工厂模式

什么是工厂设计模式?

之前我们创建类对象时,都是使用new对象的形式创建,在很多业务场景下也提供了不直接new的方式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种获取对象的方式。

工厂设计模式的作用:

  • 工厂的方法可以封装对象的创建细节,比如:为该对象进行加工和数据注入
  • 可以实现类与类之间的解耦操作(核心思想)

设计模式:装饰模式

什么是装饰设计模式?

创建一个新类,包装原始类,从而在新类中提升原来类的功能。

装饰设计模式的作用:

作用: 装饰模式指的是在不改变原类的基础上,动态地扩展一个类的功能

InputStream(抽象父类)
FileInputStream(实现子类, 读写性能较差)
BufferedInputStream(实现子类, 装饰类, 读写性能高)
  1. 定义父类
  2. 定义原始类,继承父类,定义功能。
  3. 定义装饰类,继承父类,包装原始类,增强功能!!

单例设计模式(重点)

缺点: 如果有多个单例的话,在程序一开始运行前便会占内存

作用:确保一个类只有一个对象。

场景:计算机中的回收站、任务管理器、Java中的Runtime类等

写法

  • 把类的构造器私有(保证别人不能new)
  • 在类中自己创建一个对象,并赋值到一个变量
  • 定义一个静态方法,返回自己创建的这个对象
饿汉式单例:拿对象时,对象早就创建好了。
// 单例类
public class A {
    // 2、定义一个类变量记住类的一个对象
    private static A a = new A();
    // 1、私有构造器
    private A(){ }
    // 3、定义一个类方法返回对象
    public static A getObject(){
        return a;
    }
}

懒汉式单例设计模式(重点)

第一次拿对象时,才开始创建对象
写法

  • 把类的构造器私有(保证别人不能new)
  • 在类中定义一个类变量用于存储对象(注意:此时只定义,不创建)
  • 提供一个类方法,在方法中创建并返回对象(要保证只创建一次)
public class B {
    // 2、定义一个类变量量用于存储对象
    public static B b ; // null
    // 1、单例必须私有构造器
    private B(){ }
    // 3、提供一个类方法返回类的一个对象
    public synchronized static B getObject(){
        if(b == null){
            b = new B();
        }
        return b;
    }
}

数据输入(应用)

我们可以通过 Scanner 类来获取用户的输入。使用步骤如下:

1、导包。Scanner 类在java.util包下,所以需要将该类导入。导包的语句需要定义在类的上面。

import java.util.Scanner; 

2、创建Scanner对象。

Scanner sc = new Scanner(System.in);// 创建Scanner对象,sc表示变量名,其他均不可变

3、接收数据

int i = sc.nextInt(); // 表示将键盘录入的值作为int数返回。

示例:

import java.util.Scanner;
public class ScannerDemo {
	public static void main(String[] args) {
		//创建对象
		Scanner sc = new Scanner(System.in);
		//接收数据
		int x = sc.nextInt();
		//输出数据
		System.out.println("x:" + x);
	}
}

改写三个和尚案例,数据使用键盘录入。

import java.util.Scanner;
public class ScannerTest {
	public static void main(String[] args) {
		//身高未知,采用键盘录入实现。首先导包,然后创建对象。
		Scanner sc = new Scanner(System.in);
		//键盘录入三个身高分别赋值给三个变量。
		System.out.println("请输入第一个和尚的身高:");
		int height1 = sc.nextInt();
		System.out.println("请输入第二个和尚的身高:");
		int height2 = sc.nextInt();
		System.out.println("请输入第三个和尚的身高:");
		int height3 = sc.nextInt();
		//用三元运算符获取前两个和尚的较高身高值,并用临时身高变量保存起来。
		int tempHeight = height1 > height2 ? height1 : height2;
		//用三元运算符获取临时身高值和第三个和尚身高较高值,并用最大身高变量保存。
		int maxHeight = tempHeight > height3 ? tempHeight : height3;
		//输出结果。
		System.out.println("这三个和尚中身高最高的是:" + maxHeight +"cm");
	}
}
import java.util.Scanner;
public class IfTest02 {
	public static void main(String[] args) {
		//小明的考试成绩未知,可以使用键盘录入的方式获取值
		Scanner sc = new Scanner(System.in);	
		System.out.println("请输入一个分数:");
		int score = sc.nextInt();
		//由于奖励种类较多,属于多种判断,采用if...else...if格式实现
		//为每种判断设置对应的条件
		//为每种判断设置对应的奖励	
		//数据测试:正确数据,边界数据,错误数据
		if(score>100 || score<0) {
			System.out.println("你输入的分数有误");
		} else if(score>=95 && score<=100) {
			System.out.println("山地自行车一辆");
		} else if(score>=90 && score<=94) {
			System.out.println("游乐场玩一次");
		} else if(score>=80 && score<=89) {
			System.out.println("变形金刚玩具一个");
		} else {
			System.out.println("胖揍一顿");
		}
	}
}

动态代理

程序为什么需要代理?代理长什么样?

  • 代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的。
  • 对象如果嫌身上干的事太多的话,可以通过代理来转移部分职责。
  • 对象有什么方法想被代理,代理就一定要有对应的方法

关键步骤

  • 必须有接口,实现类要实现接口(代理通常是基于接口实现的)
  • 创建一 个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。
image-20240412230747658

如何为Java对象创建一个代理对象

java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情