单例设计模式
单例设计模式介绍
单例设计模式作用就是让某个类只能有一个对象
单例设计模式实现步骤
- 将构造方法私有化【不让别人new对象】
- 在该类内部产生一个唯一的实例化对象,并且使用private static修饰
- 提供一个private static的静态方法,该方法返回这个静态对象
单例设计模式的类型
- 懒汉式:不立即创建本类的对象,当别人调用静态方法获取本类的对象时,才去创建
懒汉单例模式设计
//该类采用单例模式中的懒汉式
public class Cat {
//私有构造
private Cat() {
}
//内部定义一个Cat类的对象
private static Cat cat = null;
//提供静态方法,多线程情况下用synchronized,保证该方法对的原子性
public synchronized static Cat getInstance() {
if (cat == null) {
cat = new Cat();
}
return cat;
}
}
public class TestCat {
public static void main(String[] args){
Cat cat = Cat.getInstance();
System.out.println(cat);
}
}
- 饿汉式:先把对象创建出来,当别人调用静态方法获取本类的对象时,直接返回对象即可
饿汉单例模式设计
//要求该类采用单例模式中的饿汉式
public class Dog {
//私有化构造
private Dog() {
}
//自己定义一个对象
private static Dog dd = new Dog();
//提供一个静态方法
public static final Dog getInstance() {
return dd;
}
}
public class TestDog {
public static void main(String[] args) {
//获取Dog对象
Dog dog = Dog.getInstance();
System.out.println(dog);
}
}
多例设计模式
多例设计模式的介绍
通过多例设计模式,可以保证我们的类具有指定个数的对象
多例设计模式的实现步骤
- 私有化构造(不让别人可以正常创建对象)
- 在类内部创建一个private static集合,用于保存我们自己创建的对象
- 使用静态代码块static 向集合中添加指定个数对象
- 通过publicstatic静态方法,返回集合中的某个对象
多例设计模式代码实现
//使用多例设计模式
public class Pig {
//定义一个变量,指定个数
private static int count = 4;
//私有化构造
private Pig() {
}
//创建一个集合
private static ArrayList<Pig> list = new ArrayList<>();
//使用静态代码块
static {
//添加指定个数的对象
for (int i = 0; i < count; i++) {
list.add(new Pig());
}
}
//提供静态方法
public static Pig getInstance() {
return list.get(new Random().nextInt(count));
}
}
public class TestPig {
public static void main(String[] args) {
//获取pig对象
Pig pig1 = Pig.getInstance();
Pig pig2 = Pig.getInstance();
}
}
动态代理
概述
代理就是被代理者,没有能力完成某件事,找一个可以帮助其完成事件的对象,该对象称为代理。
代理对象中应该保存被代理对象,且代理中方法:增删改,直接抛出异常,获取方法,调用被代理对象的方法。
代码实现
//代理类
//1、代理和被代理实现同样的接口,目的是获取相同的方法
public class Array implements List<String> {
//2、要在代理对象中保存一个被代理对象
private ArrayList<String> list;
public Array(ArrayList<String> list) {
this.list = list;
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<String> iterator() {
//抛出异常
throw new UnsupportedOperationException("不允许调用");
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(String s) {
throw new UnsupportedOperationException("不允许调用");
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("不允许调用");
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public String get(int index) {
return list.get(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public List<String> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex,toIndex);
}
}
//被代理类
public class TestDemo {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
arr.add("张三");
arr.add("18");
//把集合arr交给代理对象
List<String> list = getArr(arr);
}
public static List<String> getArr(ArrayList<String> arr) {
//创建一个代理
Array array = new Array(arr);
//返回代理对象
return array;
}
}
动态代理
在运行时期通过代码动态生成,作用是:拦截对真实对象(被代理对象)方法的直接访问,增强真实对象方法的功能
案例实现
通过动态方式,在运行时期创建出来
//使用动态代理
public class TestDemo {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
arr.add("张三");
arr.add("18");
//使用arr这个集合,生成一个动态代理
List<String> list = Collections.unmodifiableList(arr);
//调用方法
list.add("李四");//不允许添加
list.set(1,"18");//可以获取数据
}
}
重点类和方法
-
java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一个静态方法来为一组接口的实现类动态地生成代理类及其对象。
-
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
ClassLoader loader:类加载器
Class[] interfaces :被代理类对象实现所有接口的字节码文件数组
InvocationHandler h:用于拦截我们调用的所有方法,判断到底是否应该是被代理对象的真实方法 -
InvocationHandler接口的invoke方法及参数详解
//invoke方法就是用于拦截我们调用的真实方法
public Object invoke(Object proxy, Method method, Object[] args)
Object proxy:代理对象
Method method:被拦截到的方法
Object[] args:被拦截到方法的参数,如果没有就是null
动态代理综合案例实现
//使用动态代理
public class TestDemo {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
arr.add("张三");
arr.add("18");
//使用arr这个集合,生成一个动态代理
List<String> list = umlist(arr);
//调用方法
//list.add("李四");//不允许添加
//list.set(1, "18");//可以获取数据
System.out.println(list.indexOf("18"));
}
public static List<String> umlist(List<String> arr) {
//使用API创建一个动态代理
List<String> list = (List<String>) Proxy.newProxyInstance(TestDemo.class.getClassLoader(), arr.getClass().getInterfaces(), new InvocationHandler() {
//该方法就是用来拦截真实对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取方法名,即需要拦截add remove set开头的方法
String name = method.getName();
if (name.startsWith("add")) {
throw new UnsupportedOperationException("不让执行");
}
if (name.startsWith("remove")) {
throw new UnsupportedOperationException("不让执行");
}
if (name.startsWith("set")) {
throw new UnsupportedOperationException("不让执行");
}
//其他方法执行【反射】
Object result = method.invoke(arr, args);
return result;
}
});
return list;
}
优缺点
优点:
1、 可以为任意接口的实现类做动态代理
2、极大提高了开发效率
3、 不会改变被代理对象的代码
缺点:
1、创建动态代理必须有接口,没有接口不行
工厂设计模式
概述
以前创建对象是通过new的方式创建, 而工厂模式是将创建对象的过程交给工厂执行,我们从中获取即可。
工厂模式的作用
解决类与类之间的耦合问题
工厂模式的实现步骤
- 提供一个所有类的接口或者父类
- 编写一个Falali类实现Car接口,重写run方法
- 编写一个Benchi类实现Car接口
- 提供一个CarFactory(汽车工厂),用于生产汽车对象
案例实现
public class BaoMa implements Car{
public void run() {
System.out.println("宝马车在跑");
}
}
public class BenChi implements Car {
public void run() {
System.out.println("奔驰车在跑");
}
}
public interface Car {
public void run();
}
//汽车工厂
public class CarFactory {
//定义一个方法,用于生产汽车
public static Car getCar(int id) {
//返回一辆真正的汽车对象
if (id == 1) {
return new BaoMa();
} else if (id == 2) {
return new BenChi();
} else {
throw new UnsupportedOperationException("id不存在");
}
}
}
public class TestCar {
public static void main(String[] args) {
//找汽车工厂
Car car = CarFactory.getCar(6);
car.run();
}
}
动态代理练习
public interface Iperson {
abstract void Sing(String name);
}
public class LiYunChun implements Iperson {
@Override
public void Sing(String name) {
System.out.println("我想听李宇春唱歌");
System.out.println(name+"李宇春唱了一首歌");
//return "心里舒服了";
}
}
public class TestProxy {
public static void main(String[] args) {
//创建被代理对象
LiYunChun liYunChun = new LiYunChun();
//根据被代理对象创建代理对象
Iperson iperson = (Iperson) Proxy.newProxyInstance(liYunChun.getClass().getClassLoader(), liYunChun.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//第一次代理对象没有增强
//method.invoke(liYunChun);//方法中没有参数
//return null;
//第二次代理对象增强,收费
System.out.println("收费10000元");
method.invoke(liYunChun, args);//方法中有参数
return null;
//第三次代理对象增强,帮忙宣传
//Object invoke = method.invoke(liYunChun, args);//有参数,有返回值
//System.out.println("记得帮忙宣传");
//return invoke;
}
});
//调用方法
iperson.Sing("我说:");//每执行一次代理对象的方法,他都会执行一次invoke方法
//System.out.println(sing);
}
}