什么是设计模式?
-
一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。
设计模式有20多种,对应20多种软件开发中会遇到的问题。
关于设计模式的学习,主要学什么?
- 解决什么问题
- 如何写
设计模式:工厂模式
什么是工厂设计模式?
之前我们创建类对象时,都是使用new对象的形式创建,在很多业务场景下也提供了不直接new的方式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种获取对象的方式。
工厂设计模式的作用:
- 工厂的方法可以封装对象的创建细节,比如:为该对象进行加工和数据注入
- 可以实现类与类之间的解耦操作(核心思想)
设计模式:装饰模式
什么是装饰设计模式?
创建一个新类,包装原始类,从而在新类中提升原来类的功能。
装饰设计模式的作用:
作用: 装饰模式指的是在不改变原类的基础上,动态地扩展一个类的功能
InputStream(抽象父类)
FileInputStream(实现子类, 读写性能较差)
BufferedInputStream(实现子类, 装饰类, 读写性能高)
- 定义父类
- 定义原始类,继承父类,定义功能。
- 定义装饰类,继承父类,包装原始类,增强功能!!
单例设计模式(重点)
缺点: 如果有多个单例的话,在程序一开始运行前便会占内存
作用:确保一个类只有一个对象。
场景:计算机中的回收站、任务管理器、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("胖揍一顿");
}
}
}
动态代理
程序为什么需要代理?代理长什么样?
- 代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的。
- 对象如果嫌身上干的事太多的话,可以通过代理来转移部分职责。
- 对象有什么方法想被代理,代理就一定要有对应的方法
关键步骤
- 必须有接口,实现类要实现接口(代理通常是基于接口实现的)
- 创建一 个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。
如何为Java对象创建一个代理对象
java.lang.reflect.Proxy
类:提供了为对象产生代理对象的方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情