工厂设计模式
什么是工厂模式
实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂(比较少)模式。
工厂模式好处
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。
将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
工厂模式分类
简单工厂模式
简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。
简单工厂的优点/缺点
优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则。
简单工厂代码:
package com.example.demo.factory;
/**
* 接口
*/
public interface Car {
void run();
}
package com.example.demo.factory;
/**
* 实现类
*/
public class BaoMa implements Car {
@Override
public void run() {
System.out.println("宝马车...");
}
}
package com.example.demo.factory;
/**
* 实现类
*/
public class BenChi implements Car {
@Override
public void run() {
System.out.println("奔驰车...");
}
}
package com.example.demo.factory;
/**
* 简单工厂 如果判断比较多的话 后期不利于维护
*/
public class CarFactory {
public static Car createCar(String name) {
if (name == null || name == "") {
return null;
}
if (name.equals("宝马")) {
return new BaoMa();
}
if (name.equals("奔驰")) {
return new BenChi();
}
return null;
}
}
package com.example.demo.factory;
public class Client {
public static void main(String[] args) {
// new 创建对象的 调用方法
// Car benChi=new BenChi();
// Car baoMa = new BaoMa();
//
// benChi.run();
// baoMa.run();
//简单工厂的调用方法
Car car = CarFactory.createCar("宝马");
car.run();
}
}
工厂方法模式
什么是工厂方法模式
工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
package com.example.demo.factory02;
/**
* 接口
*/
public interface Car {
void run();
}
package com.example.demo.factory02;
/**
* 实现类
*/
public class BaoMa implements Car {
@Override
public void run() {
System.out.println("宝马车...");
}
}
package com.example.demo.factory02;
/**
* 实现类
*/
public class BenChi implements Car {
@Override
public void run() {
System.out.println("奔驰车...");
}
}
package com.example.demo.factory02;
/**
* 工厂方法模式
*/
public interface CarFactory {
Car createCar(String name);
}
package com.example.demo.factory02;
/**
* 奔驰汽车工厂
*/
public class BenChiFactory implements CarFactory {
@Override
public Car createCar(String name) {
System.out.println("奔驰汽车...");
return new BenChi();
}
}
package com.example.demo.factory02;
/**
* 宝马汽车工厂
*/
public class BaoMaFactory implements CarFactory {
@Override
public Car createCar(String name) {
System.out.println("宝马汽车...");
return new BaoMa();
}
}
package com.example.demo.factory02;
public class Client {
public static void main(String[] args) {
// new 创建对象的 调用方法
// Car benChi=new BenChi();
// Car baoMa = new BaoMa();
//
// benChi.run();
// baoMa.run();
//工厂方法
BaoMaFactory baoMaFactory=new BaoMaFactory();
Car car = baoMaFactory.createCar("宝马");
car.run();
BenChiFactory benChiFactory=new BenChiFactory();
Car car1 = benChiFactory.createCar("奔驰");
car1.run();
}
}
抽象工厂模式
什么是抽象工厂模式
抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。
抽象工厂代码:
package com.example.demo.factory03;
/**
* 包装 组件
*/
public interface Factory {
/**
* 创建发动机
*/
Engine createEngine();
/**
* 创建座椅
* @return
*/
Chair createChair();
}
package com.example.demo.factory03;
/**
* 发动机 组件
*/
public interface Engine {
void run();
}
class EngineA implements Engine{
@Override
public void run() {
System.out.println("发动机转速快");
}
}
class EngineB implements Engine{
@Override
public void run() {
System.out.println("发动机转速慢");
}
}
package com.example.demo.factory03;
/**
* 座椅 组件
*/
public interface Chair {
void run();
}
class ChairA implements Chair{
@Override
public void run() {
System.out.println("带加热功能的座椅");
}
}
class ChairB implements Chair{
@Override
public void run() {
System.out.println("不带加热功能的座椅");
}
}
package com.example.demo.factory03;
/**
* 宝马工厂
*/
public class BaoMaFactory implements Factory {
@Override
public Engine createEngine() {
return new EngineA();
}
@Override
public Chair createChair() {
return new ChairB();
}
}
package com.example.demo.factory03;
public class Client {
public static void main(String[] args) {
Factory baoMaFactory = new BaoMaFactory();
Chair chair = baoMaFactory.createChair();
Engine engine = baoMaFactory.createEngine();
chair.run();
engine.run();
}
}
简单工厂、工厂方法、抽象工厂之小结、区别
简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)
抽象工厂 :用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族,例如车轮胎、车玻璃、车座椅等产品类型)
代理模式
什么是代理模式
通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用之前或调用后进行处理。既(AOP微实现) ,AOP核心技术面向切面编程。
代理模式应用场景
SpringAOP、事物原理、日志打印、权限控制、远程调用、安全代理 可以隐蔽真实角色
代理的分类
静态代理(静态定义代理类)
动态代理(动态生成代理类)
Jdk自带动态代理
Cglib 、javaassist(字节码操作库)
静态代理
什么是静态代理
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
静态代理代码:
package com.example.demo.factory04;
/**
* 接口
*/
public interface UserDao {
void add();
}
package com.example.demo.factory04;
/**
* 接口实现类
*/
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("执行新增操作...");
}
}
package com.example.demo.factory04;
/**
* 静态代理
*/
public class UserDaoProxy implements UserDao {
private UserDao userDao;
public UserDaoProxy(UserDao userDao){
this.userDao=userDao;
}
@Override
public void add() {
System.out.println("开启事务...");
userDao.add();
System.out.println("提交事务...");
}
}
package com.example.demo.factory04;
/**
* 静态代理 静态需要生成代理对象
* 缺点:需要生成代理对象,如果后期有多个接口处理的话 需要生成多个代理对象 不利于扩展
*/
public class UserDemo {
public static void main(String[] args) {
UserDao userDao=new UserDaoImpl();
UserDaoProxy userDaoProxy=new UserDaoProxy(userDao);
userDaoProxy.add();
}
}
动态代理
什么是动态代理
1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3.动态代理也叫做:JDK代理,接口代理
JDK动态代理
原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下)
实现方式:
1. 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
缺点:jdk动态代理,必须是面向接口,目标业务类必须实现接口
jdk动态代理代码:
package com.example.demo.factory05;
import com.example.demo.factory04.UserDao;
import com.example.demo.factory04.UserDaoImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK 动态代理对象
* 每次生成动态代理对象时,实现了InvocationHandler 接口的调用处理对象
*/
public class InvocationHandlerImpl implements InvocationHandler {
/**
* 目标代理对象
*/
private Object target;
public InvocationHandlerImpl(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//开启事务
System.out.println("动态代理开启事务");
Object invoke = method.invoke(target, args);
System.out.println("动态代理提交事务");
return invoke;
}
public static void main(String[] args) {
//被代理对象
UserDao userDao=new UserDaoImpl();
InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userDao);
//获取类加载器
ClassLoader classLoader = userDao.getClass().getClassLoader();
//获取当前实现的接口信息
Class<?>[] interfaces = userDao.getClass().getInterfaces();
//调用动态代理实例 主装载器、一组接口及调用处理动态代理实例
UserDao userDao1 = (UserDao) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
userDao1.add();
}
}
CGLIB动态代理
原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
什么是CGLIB动态代理
使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码。
CGLIB代码:
package com.example.demo.cglibproxy;
import com.example.demo.factory04.UserDao;
import com.example.demo.factory04.UserDaoImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLIB 没有接口依赖关系 底层使用字节码技术 asm
* JDK 依赖接口 因为底层使用了反射机制
*/
public class CglibProxy implements MethodInterceptor {
/**
* 目标对象
*/
private Object targetObject;
public Object getInstance(Object targetObject){
this.targetObject=targetObject;
//操作字节码 生成一个虚拟子类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObject.getClass());
//回调 返回当前对象
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
Object invoke = methodProxy.invoke(targetObject, objects);
System.out.println("提交事务");
return invoke;
}
/**
* 如何判断一个类是否实现类接口?通过反射机制
* @param args
*/
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
UserDao instance = (UserDao) cglibProxy.getInstance(new UserDaoImpl());
instance.add();
}
}
CGLIB动态代理与JDK动态区别
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
在Spring中。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。