1:场景一:工厂模式中简单工厂模式优化
1)简单工厂模式也可以叫做静态方法模式(因为工厂类一般都是在内部定义了一个静态方法)
2)简单工厂模式通过创建一个对应的工厂类,将类实例化的操作
与使用对象的操作
进行分开,让使用者不用知道具体参数就可以实例化出所需要的具体产品
类,从而避免了在客户端代码中显式指定,实现了解耦。即使用者可直接消费产品而不需要知道其生产的细节~
3)实现简单工程模式的核心是创建一个工厂类
,并且在内部定义了一个静态方法,传入不同的参数标识
通过switch
进行分组,通过new
实例化创建不同的子类对象返回~
1.1 : 步骤1:创建抽象产品类
public interface Product {
public abstract void show();
}
1.2 :创建具体的产品
public class ProductA implements Product {
@Override
public void show() {
System.out.println("生产了产品A");
}
}
public class ProductB implements Product {
@Override
public void show() {
System.out.println("生产了产品B");
}
}
public class ProductC implements Product {
@Override
public void show() {
System.out.println("生产了产品C");
}
}
1.3: 创建简单工厂类
public class SimpleFactory {
/**
* 实现简单工厂模式
* @param pName 产品标识
* @return 返回具体的产品
*/
public static Product createProduct(String pName){
switch (pName){
case "A":
return new ProductA();
case "B":
return new ProductB();
case "C":
return new ProductC();
default:
return null;
}
}
}
1.4:调用简单工厂类
public class SimpleFactoryTest {
public static void main(String[] args) {
try {
SimpleFactory.createProduct("A").show();
} catch (NullPointerException e) {
System.out.println("没有A这款产品,无法生产~");
}
try {
SimpleFactory.createProduct("B").show();
} catch (NullPointerException e) {
System.out.println("没有B这款产品,无法生产~");
}
try {
SimpleFactory.createProduct("C").show();
} catch (NullPointerException e) {
System.out.println("没有C这款产品,无法生产~");
}
try {
SimpleFactory.createProduct("D").show();
} catch (NullPointerException e) {
System.out.println("没有D这款产品,无法生产~");
}
}
}
1.5:简单工厂模式的弊端
1)操作成本高:每增加一个接口的子类,必须修改工厂类的逻辑
2)系统复杂性提高:每增加一个接口的子类,都必须向工厂类添加逻辑
1.6:简单工厂模式优化思路
采用Java反射机制,通过传入子类全局定名(包名+类名)
动态的创建不同的子类对象实例
,从而使得在不增加产品接口子类和修改工厂类的逻辑的情况下还能实现了工厂类对子类实例对象的统一创建~
1.6.1 :创建工厂类
采用Java反射机制对工厂类进行优化,主要是将className
即子类全局定名(包名+类名)
作为入参,通过Class.forName
方式获取类的java.lang.Class
实例对象,再通过Class
实例对象的getInstance
方法获取到具体子类的实例对象~
public class Factory {
public static Product getInstance(String className) {
Product realProduct = null;
try {
Class pClass = Class.forName(className);
realProduct = (Product) pClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return realProduct;
}
}
1.6.2 :调用工厂类测试
public class FactoryTest {
public static void main(String[] args) {
try {
Product productA = Factory.getInstance("com.justin.java.lang.ProductA");
productA.show();
} catch (NullPointerException e) {
System.out.println("没有A这款产品,无法生产~");
}
try {
Product productB = Factory.getInstance("com.justin.java.lang.ProductB");
productB.show();
} catch (NullPointerException e) {
System.out.println("没有B这款产品,无法生产~");
}
try {
Product productC = Factory.getInstance("com.justin.java.lang.ProductC");
productC.show();
} catch (NullPointerException e) {
System.out.println("没有C这款产品,无法生产~");
}
try {
Product productD = Factory.getInstance("com.justin.java.lang.ProductD");
productD.show();
} catch (Exception e) {
System.out.println("没有D这款产品,无法生产~");
}
}
}
1.7 :通过配置文件的形式再次对简单工厂模式进行优化
通过配置文件
方式,统一定义类名对应全局定名(包名+类名)
,将配置文件存放到资源目录下,程序运行时通过ClassLoader
类加载器动态获取到配置文件
中定义的子类的全局定名~
1.7.1 :配置类名对应全局定名(包名+类名)
创建属性配置文件:Product.properties
//产品抽象类Product相关子类的全局定名(包名+类名)定义
ProductA = com.justin.java.lang.ProductA
ProductB = com.justin.java.lang.ProductB
ProductC = com.justin.java.lang.ProductC
1.7.2 : 调用工厂类进行测试
public class FactoryTest {
@Test
public void test() throws IOException {
ClassLoader classLoader = this.getClass().getClassLoader();
Properties prop = new Properties();
prop.load(classLoader.getResourceAsStream("Product.properties"));
String className = "";
try {
className = prop.getProperty("ProductA");
Product productA = Factory.getInstance(className);
productA.show();
} catch (NullPointerException e) {
System.out.println("没有A这款产品,无法生产~");
}
try {
className = prop.getProperty("ProductB");
Product productA = Factory.getInstance(className);
productA.show();
} catch (NullPointerException e) {
System.out.println("没有B这款产品,无法生产~");
}
try {
className = prop.getProperty("ProductC");
Product productA = Factory.getInstance(className);
productA.show();
} catch (NullPointerException e) {
System.out.println("没有C这款产品,无法生产~");
}
}
}
2:场景二: 代理模式中动态代理应用及Aop实现
1)代理(Proxy)模式
是一种设计模式
,通过代理对象
来访问目标对象
,还可以在不修改目标对象
的情况下,对代理对象
进行拓展,增强目标对象
的功能~
2)静态代理:
静态代理
属于代理模式
的一种代理方式,需要代理对象
和目标对象
实现相同的接口静态代理
的代理类是由程序员编写源码,编译后即可获取到代理类的class字节码文件,也就是在程序运行前
就已经得到实际的代理类class字节码文件了
3)动态代理:
(1)动态代理
也属于代理模式
的一种代理方式,不过只需要目标对象
实现接口,代理对象
不需要实现接口~
(2)动态代理
的代理类编译后是没有class字节码文件的,而是在运行时利用Java反射机制
动态的生成代理类的class字节码文件~
(3)JDK 原生动态代理,主要利用了JDK API
的java.lang.reflect.Proxy
和java.lang.relfect.InnvocationHandler
这两个类来实现~
通过java.lang.reflect.Proxy
代理类的newProxyInstance
方法,传递3个参数,分别是:目标对象的加载器
通过MyClass.getClass().getClassLoader
方式获取目标对象的实现接口类型
通过Object.getClass().getInterfaces()
方式获取InnvocationHandler事件处理器
通过new
实例化对象并重写invoke
方法方式获取
2.1 静态代理示例
用户接口类 IUserDao
public interface IUserDao {
//添加数据
public void insert();
}
目标对象类 UserDao
public class UserDao implements IUserDao{
@Override
public void insert() {
System.out.println("添加数据");
}
}
2.2 :动态代理示例
public class UserProxy {
private Object target; //目标对象
public UserProxy(Object target) {
this.target = target;
}
/**
* 利用JDK API获取到代理对象
* @return
*/
public Object getProxyInstance() {
//目标对象的加载器
ClassLoader loader = target.getClass().getClassLoader();
//目标对象的实现接口类型
Class<?>[] interfaces = target.getClass().getInterfaces();
//InnvocationHandler事件处理器实例对象
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("添加数据前:手动开启事务");
// 执行目标对象方法
Object value = method.invoke(target, args);
System.out.println("添加数据后:手动提交事务");
return null;
}
};
//传入3个参数,创建代理类的实例对象,并返回
return Proxy.newProxyInstance(loader, interfaces,h);
}
}
动态代理测试
public class UserProxyTest {
@Test
public void test() {
IUserDao target = new UserDao();
System.out.println("目标对象信息:" + target.getClass());
//获取代理类实例对象
IUserDao proxy = (IUserDao) new UserProxy(target).getProxyInstance();
System.out.println("代理对象信息:" + proxy.getClass());
//执行代理方法
proxy.insert();
}
}
打印结果:
目标对象信息:class com.justin.java.reflect.UserDao
代理对象信息:class com.sun.proxy.$Proxy2
添加数据前:手动开启事务
添加数据
添加数据后:手动提交事务