17.静态代理

 

代理模式

它是一种软件开发设计模式

使用代理的目地:因为目标对象无法满足用户的需求,所以使用代理类来增强目标对象

1.代理的分类

静态代理
|–IO里面的静态代理使用的相当多
动态代理
|–jdk动态代理
|–cglib的动态代理

静态代理

1.使用继承实现静态代理

目标类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.course.curd;

public class DatabaseCurd {

public void add() {
System.out.println("insert data into table");
}

public void update() {
System.out.println("update table data");
}

public void delete() {
System.out.println("delete table data");
}

public void query() {
System.out.println("query table data");
}

}

代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.course.extend;

import com.course.curd.DatabaseCurd;

public class DatabaseDML extends DatabaseCurd{

public void add() {
openConnection();
super.add();
closeConnnection();
}

public void openConnection() {
System.out.println("conn.open()");
}

public void closeConnnection() {
System.out.println("conn.close()");
}

}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.course.test;

import com.course.curd.DatabaseCurd;
import com.course.decorator.DatabaseOperate;
import com.course.extend.DatabaseDML;

public class Test {

public static void main(String[] args) {
DatabaseDML databaseDML = new DatabaseDML();
databaseDML.add();
// conn.open()
// insert data into table
// conn.close()
}
}

2.使用装饰者模式实现静态代理

目标类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.course.curd;

public class DatabaseCurd {

public void add() {
System.out.println("insert data into table");
}

public void update() {
System.out.println("update table data");
}

public void delete() {
System.out.println("delete table data");
}

public void query() {
System.out.println("query table data");
}

}

代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.course.decorator;

import com.course.curd.DatabaseCurd;

public class DatabaseOperate {

private DatabaseCurd databaseCurd;

public DatabaseOperate(DatabaseCurd databaseCurd) {
this.databaseCurd = databaseCurd;
}

public void query() {
openConnection();
databaseCurd.query();
closeConnnection();
}

public void openConnection() {
System.out.println("conn.open()");
}

public void closeConnnection() {
System.out.println("conn.close()");
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.course.test;

import com.course.curd.DatabaseCurd;
import com.course.decorator.DatabaseOperate;
import com.course.extend.DatabaseDML;

public class Test {

public static void main(String[] args) {
DatabaseCurd databaseCurd = new DatabaseCurd();
DatabaseOperate databaseOperate = new DatabaseOperate(databaseCurd);
databaseOperate.query();
// conn.open()
// query table data
// conn.close()
}
}

3.常见方法(使用接口)

为了保证代理类与目标类的对应方法的方法名一致,可以使用接口的方式。

目标类与代理类都实现同一个接口。

接口

1
2
3
4
5
package com.course.dao;

public interface UserDao {
public void addUser();
}
1
2
3
4
5
package com.course.dao;

public interface DepartmentDao {
public void addDepartmentDao();
}

目标类

1
2
3
4
5
6
7
8
9
10
11
12
package com.course.dao.impl;

import com.course.dao.UserDao;

public class UserDaoImpl implements UserDao {

@Override
public void addUser() {
System.out.println("Save user");

}
}
1
2
3
4
5
6
7
8
9
10
11
12
package com.course.dao.impl;

import com.course.dao.DepartmentDao;

public class DepartmentDaoImpl implements DepartmentDao {

@Override
public void addDepartmentDao() {
System.out.println("Save department");

}
}

代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.course.proxy;

import com.course.dao.UserDao;

public class UserDaoProxy implements UserDao {

private UserDao userDao;

public UserDaoProxy(UserDao userDao) {
this.userDao = userDao;
}

@Override
public void addUser() {
System.out.println("open transaction");
userDao.addUser();
System.out.println("commit transaction");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.course.proxy;

import com.course.dao.DepartmentDao;

public class DepartmentDaoProxy implements DepartmentDao {

private DepartmentDao departmentDao;

public DepartmentDaoProxy(DepartmentDao departmentDao) {
this.departmentDao = departmentDao;
}

@Override
public void addDepartmentDao() {
System.out.println("open transaction");
departmentDao.addDepartmentDao();
System.out.println("commit transaction");
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.course.test;

import com.course.dao.DepartmentDao;
import com.course.dao.UserDao;
import com.course.dao.impl.DepartmentDaoImpl;
import com.course.dao.impl.UserDaoImpl;
import com.course.proxy.DepartmentDaoProxy;
import com.course.proxy.UserDaoProxy;

public class Test {

public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
userDaoProxy.addUser();
// open transaction
// Save user
// commit transaction

DepartmentDao departmentDao = new DepartmentDaoImpl();
DepartmentDaoProxy departmentDaoProxy = new DepartmentDaoProxy(departmentDao);
departmentDaoProxy.addDepartmentDao();
// open transaction
// Save department
// commit transaction
}
}

3.静态代理说明

在JDK的IO流里面大量使用了静态代理,可以去看看源代码

4.静态代理总结:
(1) 可以做到在不修改目标对象的功能前提下,对目标功能扩展.
(2) 缺点:

因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多。

每有一个目标类就需要有一个代理类,目标类每添加一个方法,就需要在代理类中添加相应的方法,这样就会有很多代理类,很难维护。

如何解决静态代理中的缺点呢?答案是可以使用动态代理方式