好了,正传开始,此处已无男神,区区在下小女子目下无尘,只有代码。

      现在,我们开始假装要搞一个商城了。商城先得有商品吧,有商品就得把商品存到数据库里去吧。那我们就在此顺势建一个将商品持久化的类。(注:此处可能有小朋友会举手问什么是持久化,持久化你目前可以理解为就是把商品的数据保存到数据库里,以后想看,可以拿出来看。持久化了的东东,就不是只活在内存里,一关机就不见了。而是放到数据库里,保存到硬盘上了的。如果还有小朋友想问什么是内存,什么是硬盘,来,我慢慢告诉你,放心,我不得打小朋友的)。

将商品保存到数据库,增删改查是必须的。但暂时不理它。(注:查我们要单独处理,容后再说。)

就此决定,先建三个方法:增删改:

第一代代码

商品持久化类 ProductDaoImpl

public class ProductDaoImpl {
 
public void insert(){
   
System.out.println("新增商品");
  }
 
public void update(){
   
System.out.println("修改商品");
  }
 
public void delete(){
   
System.out.println("删除商品");
  }
}

客户端测试

public class ProxyTest {

public static void main(String[] args) {

ProductDaoImpl productDao=new ProductDaoImpl ();

productDao.delete();

}

}

正常运行,打印出"删除商品" 没有问题。

好了,这三个特别特别复杂的方法我们写好了,核心功能都实现了(是吧,是吧,都打印出来了的)。然后,对数据库操作,得有事务吧(不懂什么是事务的小朋友请举手,我们另外处理。),得写日志吧,还得先判断当前登录用户对这个商品是否有操作权限吧?(注:看明白了吧?至少确实不能开个事务来独占资源,所以不一起说。)

于是,这三个特别复杂的方法瞬间又上一个档次的复杂了起来。

第二代代码

public class ProductDaoImpl {

public void insert(){

System.out.println("判断是否有操作权限");

System.out.println("开始事务");

System.out.println("新增商品");

System.out.println("结束事务");

System.out.println("写日志");

}

public void update(){

System.out.println("判断是否有操作权限");

System.out.println("开始事务");

System.out.println("修改商品");

System.out.println("结束事务");

System.out.println("写日志");

}

public void delete(){

System.out.println("判断是否有操作权限");

System.out.println("开始事务");

System.out.println("删除商品");

System.out.println("结束事务");

System.out.println("写日志");

}

}

代码这么多,还大多是重复的,这不应该是人干的活,这应该是ChatGPT干的事儿哇~~纵观以上代码,每个方法中,核心业务只有一行,边边角角,又必须存在的代码有4行之多。所以,我们必须想个办法消灭它们,让我们核心突出。

主角得有主角的待遇

所以,我们另外建一个类,专注处理边边角角,可以吗?那是当然。来,走起。

新建一个代理类ProxyDao

1.    首先,这个代理类有商品持久化类ProductDaoImpl的各同名方法。

public class ProxyDao {

public void insert(){}

public void update(){}

public void delete(){}

}

2.    类里只需要一个成员变量productDao,该成员变量的类型就是ProductDaoImpl


public class ProxyDao {

            private ProductDaoImpl productDao;

    public void insert(){}
public void update(){}
public void delete(){}
}

3.      要保证只要代理类ProxyDao的对象被创建,其属性productDao就必须是一个已构建好的ProductDaoImpl的对象,而不会是null。所以用带参构造方法给productDao赋初值。ProxyDao只有一个构造方法,是带一个参数的构造方法,参数就是ProductDaoImpl的对象。

public class ProxyDao {
private ProductDaoImpl productDao;

         public ProxyDao(ProductDaoImpl productDao){

             this.productDao=productDao;

        }


public void insert(){}

public void update(){}

public void delete(){}

}

4.    在代理类ProxyDao的各方法中,调用属性productDao的同名方法。

public class ProxyDao {

 private  ProductDaoImpl productDao;

 public ProxyDao(ProductDaoImpl productDao){

   this.productDao=productDao;

 }

 public void insert();

   productDao.insert();

   }

 public void update(){

    productDao.update();

   }

 public void delete(){

   productDao.delete();

    }

}

代码写到这里,相信大家也看出来了,我们使用这个代理类ProxyDao的各个方法,与直接使用商品持久化类ProductDaoImpl的各个方法,产生的效果是一样的。那么,如果我们在代理类ProxyDao的各方法前后各加一些边边角角的内容呢? 象这样?

public class ProxyDao {

 private ProductDaoImpl productDao;

 public ProxyDao(ProductDaoImpl productDao){

   this.productDao=productDao;

 }


 public void insert(){

     System.out.println("判断是否有操作权限");

     System.out.println("开始事务");

     productDao.insert();

     System.out.println("结束事务");

     System.out.println("写日志");

   }


 public void update(){

     System.out.println("判断是否有操作权限");

     System.out.println("开始事务");

     productDao.update();

    System.out.println("结束事务");

     System.out.println("写日志");

   }


 public void delete(){

     System.out.println("判断是否有操作权限");

     System.out.println("开始事务");

     productDao.delete();

     System.out.println("结束事务");

     System.out.println("写日志");

   }

}

这样是不是商品持久化类ProductDaoImpl中的代码,只需要保留核心的那一行代码就可以了?

此时客户端测试,就不是直接调商品持久化类ProductDaoImpl对象的方法了,而是调代理类ProxyDao对象的方法。

public class ProxyTest {

 public static void main(String[] args) {

     ProductDaoImpl productDao=new ProductDaoImpl ();

     ProxyDao proxyDao=new ProxyDao(productDao);

     proxyDao.delete();

}

再观察一下,我们还可以把代理类ProxyDao中重复的代码再抽一抽,该封装就封装一哈。

在客户端,productDao这个变量也只是做为参数传一传,就没用了。调方法根本不关它事,于是,感觉它可以不必拥有姓名?我们在new 代理类对象的时候,传一个商品持久化类ProductDaoImpl的匿名对象进去,不香吗?外面根本找不到,不用在客户端扰我视线,乱我思维。

于是最后代码成了这样

第三代代码

代理类ProxyDao

属性productDao是商品持久化类ProductDaoImpl的对象。并通过一个有参构造进行初始化。

ProxyDao类中有与ProductDaoImpl类相同的public方法,用于调用ProductDaoImpl类中的同名方法,处理核心业务。并在调用前后,进行事务、日志、判断操作权限等非核心的相关业务的处理。

注:此例中,将核心功能前后的业务处理都设计为相同,并分别封装在begin()和last()两个私有方法中。实际应用中,可根据具体情况进行处理。

public class ProxyDao {

private ProductDaoImpl productDao;

public ProxyDao(ProductDaoImpl productDao){

this.productDao=productDao;

}

public void insert(){

begin();

productDao.insert();

last();

}

public void update(){

begin();

productDao.update();

last();

}

public void delete(){

begin();

productDao.delete();

last();

}

private void begin(){

System.out.println("判断是否有操作权限");

System.out.println("开始事务");

}

private void last(){

System.out.println("结束事务");

System.out.println("写日志");

}

}

被代理的类

商品持久化类ProductDaoImpl又恢复了原样,边边角角都交给别人去处理了,拒绝拼盘,从代理做起。

public class ProductDaoImpl {
public void insert(){
System.out.println("新增商品");
}
public void update(){
System.out.println("修改商品");
}
public void delete(){
System.out.println("删除商品");
}
}


测试类

此时客户端测试

public class ProxyTest {
public static void main(String[] args) {
ProxyDao proxyDao=new ProxyDao(new ProductDaoImpl());
proxyDao.delete();
}
}

运行结果:

代理模式(二)-静态代理(java版)_Java

代理了?对不对?代理了哇。别激动,这才刚开始呢。

这个时候呢,我们就得思考了,商城哇,怎么也得有订单吧?订单呢?要不来个订单持久化先?

于是订单持久化来了

新增的类订单持久化类OrderDaoImpl

public class OrderDaoImpl {

public void insert(){

System.out.println("新增订单");

}

public void update(){

System.out.println("修改订单");

}

public void delete(){

System.out.println("删除订单");

}

}

那订单持久化的边边角角怎么办呢?又搞一个代理类?格局小了吧~~

此时,理应接口闪亮登场了~~请跟着我念:面向接口编程~~

增加一个接口,并修改两个地方:

1.    接口有增删改三个方法,与商品持久化类ProductDaoImpl的方法一致。

2.    订单持久化类OrderDaoImpl和商品持久化类ProductDaoImpl都实现这个接口

3.    代理类ProxyDao的成员变量改为接口,构造方法的形参也改为接口。

代码如下:

第四代代码

接口IGeneralDao

public interface IGeneralDao {

void insert();

void update();

void delete();

}

代理类ProxyDao

public class ProxyDao {

 private IGeneralDao generalDao;

 public ProxyDao(IGeneralDao generalDao){

   this.generalDao=generalDao;

 }

 public void insert(){

   begin();

   generalDao.insert();

   last();

 }


 public void update(){

   begin();

   generalDao.update();

   last();

 }


 public void delete(){

   begin();

   generalDao.delete();

   last();

 }


 private void begin(){

   System.out.println("判断是否有操作权限");

   System.out.println("开始事务");

 }


 private void last(){

   System.out.println("结束事务");

   System.out.println("写日志");

 }

}

两个被代理的类

商品持久化类ProductDaoImpl

public class ProductDaoImpl implements IGeneralDao {

 public void insert(){

   System.out.println("新增商品");

 }

 public void update(){

   System.out.println("修改商品");

 }

 public void delete(){

   System.out.println("删除商品");

 }

}

 

订单持久化类OrderDaoImpl

public class OrderDaoImpl implements IGeneralDao {

 public void insert(){

   System.out.println("新增订单");

 }

 public void update(){

   System.out.println("修改订单");

 }

 public void delete(){

   System.out.println("删除订单");

 }

}

写到这里,是不是觉得想怎么代理就怎么代理了?轻松方便?

搞个测试?

测试类

public class ProxyTest {

public static void main(String[] args) {
ProxyDao proxyDao=new ProxyDao(new ProductDaoImpl());
proxyDao.delete();
System.out.println("-----------------------------");
ProxyDao proxyDao2=new ProxyDao(new OrderDaoImpl());
proxyDao2.insert();
}
}

运行结果:

代理模式(二)-静态代理(java版)_设计模式_02

好象挺完美了?世界有我,我有世界~~

但是,你以为就这样结束了吗?告诉你,并没有~~~

那设计模式,不是开玩笑的,是老几辈优秀的科学家智慧的结晶,严谨得很的~~(注:是的,long long ago之前的程序员这活,只有科学家才干得了~~)

谁能思考出哪里不严谨吗?举手没奖。

那个,代理类ProxyDao的几个public方法,是不是要和被代理的类的方法一致呀?所以呢,ProxyDao是不是也可以和被代理的类实现同一个接口呢?这样就能保证两者的方法一致,不至于被写错了?请再跟着我念:面向接口编程~~

所以,最后一改,就是把ProxyDao类改成接口的实现类。

本次静态代理模式示例代码最终的完整呈现如下:

静态代理模式代码

接口

public interface IGeneralDao {

void insert();

void update();

void delete();

}

代理类

public class ProxyDao implements IGeneralDao {

 private IGeneralDao generalDao;

 public ProxyDao(IGeneralDao generalDao){

   this.generalDao=generalDao;

 }


 public void insert(){

   begin();

   generalDao.insert();

   last();

 }


 public void update(){

   begin();

   generalDao.update();

   last();

 }


 public void delete(){

   begin();

   generalDao.delete();

   last();

 }


 private void begin(){

   System.out.println("判断是否有操作权限");

   System.out.println("开始事务");

 }


 private void last(){

   System.out.println("结束事务");

   System.out.println("写日志");

 }

}

两个被代理的类

商品持久化类

public class ProductDaoImpl implements IGeneralDao {

public void insert(){

System.out.println("新增商品");

}

public void update(){

System.out.println("修改商品");

}

public void delete(){

System.out.println("删除商品");

}

}

 

订单持久化类

public class OrderDaoImpl implements IGeneralDao {

public void insert(){

System.out.println("新增订单");

}

public void update(){

System.out.println("修改订单");

}

public void delete(){

System.out.println("删除订单");

}

}

测试类

public class ProxyTest {

 public static void main(String[] args) {

     IGeneralDao proxyDao=new ProxyDao(new ProductDaoImpl());

     proxyDao.delete();

     System.out.println("-----------------------------");

     proxyDao=new ProxyDao(new OrderDaoImpl());

     proxyDao.insert();

 }

}

运行结果:

代理模式(二)-静态代理(java版)_设计模式_03

好了,静态代理打完收工。都到这份上了,类图可以自己画否?