前言
推荐看这篇文章之前先了解Java日记之设计模式初探。
结构型设计模式总共有7种
1.外观模式
2.装饰者模式
3.适配器模式
4.享元模式
5.组合模式
6.桥接模式
7.代理模式
1.外观模式
定义:又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。和外观模式相关的设计模式有中介者模式。
适用场景:子系统越来越复杂,增加外观模式提供简单调用接口。构建多层系统结构,利用外观对象作为每层的入口,简化层间调用。
优点:简化了调用过程,无需深入了解系统,防止带来风险。减少系统依赖,松散耦合。可以更好的划分访问层次。同时符合迪米特法则,即最少知道原则。
缺点:增加子系统,扩展子系统行为容易引入风险,不符合开闭原则。
代码举例:
//物品实体类
public class PointsGift {
private String name;
public PointsGift(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//支付子系统
public class PointsPaymentService {
public boolean pay(PointsGift pointsGift) {
//扣减积分逻辑
System.out.println("支付" + pointsGift.getName() + "积分成功");
return true;
}
}
//校验子系统
public class QualifyService {
public boolean isAvailable(PointsGift pointsGift) {
System.out.println("校验" + pointsGift.getName() + "积分资格通过,库存通过");
return true;
}
}
//物流子系统
public class ShippingService {
//返回订单号
public String shipGift(PointsGift pointsGift){
//物流系统的对接逻辑
System.out.println(pointsGift.getName()+"进入物流系统");
String shippingOrderNo = "666";
return shippingOrderNo;
}
}
//外观类
public class GiftExchangeService {
private QualifyService qualifyService = new QualifyService();
private PointsPaymentService pointsPaymentService = new PointsPaymentService();
private ShippingService shippingService = new ShippingService();
public void giftExchange(PointsGift pointsGift) {
//资格校验通过
if (qualifyService.isAvailable(pointsGift)) {
//支付通过
if (pointsPaymentService.pay(pointsGift)) {
//返回订单号
String shippingOrderNo = shippingService.shipGift(pointsGift);
System.out.println("物流系统下单成功,订单号是:" + shippingOrderNo);
}
} else {
//不通过
//TODO
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
PointsGift pointsGift = new PointsGift("T桖");
//正常来说可以通过spring注入
GiftExchangeService giftExchangeService = new GiftExchangeService();
giftExchangeService.giftExchange(pointsGift);
}
}
我们举个例子,比如有一个积分商城,你需要去进行换购物品,这时候就需要经过积分校验-支付-进入物流这3个过程,也就是3个子系统,而外观类呢就是把这3个子系统结合在一起,我们应用层只需要和外观类交互就可以换购1个商品,而不不用去在意那3个子系统的哪个先调用和一些其中具体的逻辑,从UML图也可以看出外观模式的核心思想就是应用层不要跟子系统去相连,只要通过外观类联系就好了,当然外观类也可以改成抽象外观类,这个就需要通过具体的业务逻辑判断了。
2.装饰者模式
定义:在不改变原有对象的基础之上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象的功能)。这个模式在生活中还是挺常见的,比如买个蛋糕,我想加个巧克力,慕斯之类的。根据不同的需求来装饰。装饰者模式本身也是用了继承。继承是扩展形式之一,但不是弹性设计的最佳方式。
适用场景:扩展一个类的功能或给一个类附加职责。可以动态的给一个对象添加功能,这些功能也可以动态的撤销。
优点:继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能。通过使用不同装饰以及这些装饰类的排列组合,可以实现不同的效果。符合开闭原则。
缺点:会出现更多的代码,更多的类,增加程序复杂性。动态装饰时,多层装饰时会使程序更复杂。
相关设计模式:装饰者模式关注在一个对象上动态的添加方法。代理模式关注于控制对对象的访问,代理模式中的代理类可以对他的客户隐藏一个对象的具体信息。还有一个相关的就是,装饰者和适配器模式,它们都可以叫作包装模式,装饰者和被装饰者可以实现相同的接口,或者装饰者是被装饰者的子类。适配器中,适配器和被适配的具有不同的接口。当然有少数重合的接口。
代码举例:
//煎饼抽象类
public abstract class ABatterCake {
public abstract String getDesc();
public abstract int cost();
}
//煎饼实体类
public class BatterCake extends ABatterCake{
@Override
public String getDesc() {
return "煎饼";
}
@Override
public int cost() {
return 8;
}
}
//装饰者模式抽象类
public abstract class AbstractDecorator extends ABatterCake {
//持有抽象煎饼的引用
private ABatterCake aBatterCake;
protected abstract void odSomething();
public AbstractDecorator(ABatterCake aBatterCake) {
this.aBatterCake = aBatterCake;
}
@Override
public String getDesc() {
return aBatterCake.getDesc();
}
@Override
public int cost() {
return aBatterCake.cost();
}
}
这里举例一个场景,单位楼下有一个卖煎饼的,然后在单位的茶水间吃早餐,有时候加1个蛋或者香肠。这时候我们就需要装饰者模式了,我们首先定义1个煎饼的抽象类,还有最需要的装饰者抽象类,,我们这里持有抽象煎饼类的引用,接下来,我们该怎么给这个煎饼添加鸡蛋和香肠呢。代码如下:
//加蛋的类
public class EggDecorator extends AbstractDecorator {
@Override
protected void odSomething() {
}
public EggDecorator(ABatterCake aBatterCake) {
super(aBatterCake);
}
@Override
public String getDesc() {
return super.getDesc() + "加1个煎蛋 ";
}
@Override
public int cost() {
return super.cost() + 1;
}
}
//加香肠的类
public class SausageDecorator extends AbstractDecorator {
@Override
protected void odSomething() {
}
public SausageDecorator(ABatterCake aBatterCake) {
super(aBatterCake);
}
@Override
public String getDesc() {
return super.getDesc() + "加1根香肠 ";
}
@Override
public int cost() {
return super.cost() + 2;
}
}
//测试类
public class Test {
public static void main(String[] args) {
ABatterCake aBatterCake;
aBatterCake = new BatterCake();
aBatterCake = new EggDecorator(aBatterCake);
aBatterCake = new SausageDecorator(aBatterCake);
aBatterCake = new EggDecorator(aBatterCake);
System.out.println(aBatterCake.getDesc() + "销售价格:" + aBatterCake.cost());
}
}
我们让香肠类和蛋糕类去继承装饰者类,因为装饰者类不是无参的构造函数,所以我们要实现构造方法。然后通过装饰者模式来返回新的对象。这样子我们需要加香肠还是煎蛋,只需要重新new一个,然后获得新的返回对象就行。我们从UML中也可以看到,煎蛋类和香肠类是同级的。
3.适配器模式
定义:将一个类的接口转换成客户期望的另一个接口。使原本接口不兼容的类可以一起工作。
应用场景:已经存在的类,它的方法和需求不匹配时,也就是方法结果相同或者想相似。这个设计模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品,不同厂家造成功能类似而接口不相同的情况下的解决方案。
优点:能提高类的透明性和复用,现有的类但不需要改变。目标类和适配器解耦,提高程序扩展性。符合开闭原则。
缺点:适配器模式编写过程中需要全面的考虑,可能会增加系统的复杂性。另外会增加系统代码可读的难度。
扩展:对象适配器(符合组合复用原则,并且使用委托机制)。类适配器(使用类继承来实现的)。
适配器和外观模式都是对现有的类进行封装,外观定义了新的接口,适配器则是复用一个原有的接口,适配器是使2个已有的接口协同工作,而外观则是在系统中提供一个更方便的访问入口,这两个最大的区别就是适配力度不同,外观模式是用来适配整个子系统,外观所针对的对象力度更大。
类适配器模式
代码举例:
//被适配者
public class Adaptee {
public void adapteeRequest(){
System.out.println("被适配者的方法");
}
}
//转换接口
public interface Target {
void request();
}
//适配器
public class Adapter extends Adaptee implements Target{
@Override
public void request() {
//添加各种逻辑代码
super.adapteeRequest();
}
}
//实现类
public class ConcreteTarget implements Target{
@Override
public void request() {
System.out.println("concreteTarget目标方法");
}
}
//测试类
public class Test {
public static void main(String[] args) {
Target target = new ConcreteTarget();
target.request();
Target adapterTarget = new Adapter();
adapterTarget.request();
}
}
首先建立一个被适配者的类,然后建立一个实现类ConcreteTarget,接下来我们就需要一个适配器Adapter来进行适配器,这个Adapter要继承被适配器的类和Target接口。这样我们的接口就可以通过Adapter来实现了。也就是说Target的具体实现通过Adapter已经移交给了Adaptee,这就是类适配器,这里强调的是继承,通过继承来获取被适配者的一些方法,我们可以在request()
添加各种逻辑代码。
对象适配器模式
//适配器类
public class Adapter implements Target{
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
......
adaptee.adapteeRequest();
}
}
其它的代码不变,变就是适配器类,这里不通过继承,直接通过持有Adaptee的引用来进行组合。结果不变。
我们这里在举一个变压器的例子,来理解适配器设计模式。
//220V电压
public class AC220 {
public int outPutAC220V() {
int outPut = 220;
System.out.println("输出交流电" + outPut + "V");
return outPut;
}
}
//5V直流电
public interface DC5 {
int outputDC5V();
}
//适配器类
public class PowerAdapter implements DC5 {
AC220 ac220 = new AC220();
@Override
public int outputDC5V() {
int adapterInput = ac220.outPutAC220V();
//变压器
int adapterOutput = adapterInput / 44;
System.out.println("使用PowerAdapter输入AC:" + adapterInput + "V" + "输出DC:" + adapterOutput + "V");
return adapterOutput;
}
}
//测试类
public class Test {
public static void main(String[] args) {
DC5 dc5 = new PowerAdapter();
dc5.outputDC5V();
}
}
从上诉代码可以看出,220V就是一个被适配者的类,然后我们通过变压器(也就是适配器类)来适配输出AC,这样就可以进行转换了。
享元模式
定义:提供了减少对象数量从而改善应用所需要的对象结构的方式。运用共享技术有效地支持大量细粒度的对象。一句话,就是减少创建对象的数量,从而减少内存的占用,提高性能。
适用场景:系统底层的开发,以便解决系统的性能问题。还有系统有大量的相似对象,需要换冲刺的场景。
优点:减少对象的创建,降低内存中的对象数量,降低系统的内存,同时提高了效率。还有就是减少内存之外的其他资源的占用(比如时间等,因为new一个对象需要消耗时间)。
缺点:关注内部/外部状态,关注线程安全问题。是系统程序的逻辑复杂化。
扩展:内部状态(是指在享元对象的内部并且不会随着环境改变而改变的共享部分,也就是说外部环境怎么变话,内部都不会变)。外部状态(那随着环境改变的状态就是外部状态,这种状态是不可以共享的状态,是记录在享元对象的外部)。通俗一点,内部状态可以认为是享元对象的属性,这个属性不会随着外部的环境变化而变化。外部状态的话就是我们在调用享元模式获取享元对象的时候,我们通过方法的参数传过来一个状态,例如说int = 0的时候是怎么样,1的时候是怎么样。
相关设计模式:代理模式(需要一个代理类,需要花费资源,那么就可以用享元模式提高速度)。单例模式(容器单例就是和享元模式的一个结合)。
代码举例:
我们现在有一个场景,一个公司要求各个部门的管理者做年底总结报告,如果报告已经生成过了,就没必要就去new一个了。这里也会结合工程模式。
//经理功能接口
public interface Employee {
void report();
}
//经理
public class Manager implements Employee {
//所在部门
private String department;
//报告内容
private String reportContent;
public Manager(String department) {
this.department = department;
}
@Override
public void report() {
System.out.println(reportContent);
}
public String getReportContent() {
return reportContent;
}
public void setReportContent(String reportContent) {
this.reportContent = reportContent;
}
}
//工厂模式
public class EmployeeFactory {
//容器单例
private static final Map EMPLOYEE_MAP = new HashMap<>();
public static Employee getManager(String department) {
Manager manager = (Manager) EMPLOYEE_MAP.get(department);
if (manager == null) {
manager = new Manager(department);
System.out.print("创建部门经理:" + department);
String reportContent = department + "部门汇报:此次报告的主要内容是******";
manager.setReportContent(reportContent);
System.out.println(" 创建报告:" + reportContent);
EMPLOYEE_MAP.put(department, manager);
}
return manager;
}
}
//测试类
public class Test {
private static final String[] departments = {"RD", "QA", "PM", "BD"};
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
//随机叫部门报告
String department = departments[(int) (Math.random() * departments.length)];
Manager manager = (Manager) EmployeeFactory.getManager(department);
manager.report();
}
}
}
从上述代码就可以看出EMPLOYEE_MAP就是享元模式的缓冲池,每次叫部门做报告的时候,如果没有做报告的就会new一个报告出来,如果之前已经报告过的,就直接从缓冲池里进行报告,不用再次创建报告。对于部门经理,也就是department,它是声明在外部的,并且manager的department这个状态依赖于外部传入的参数,所以可以认为它是外部状态,因为传入不同的department,获得的manager的department这个属性是不一样的,对于Manager这个类的实体,我们就可以认为department是外部状态,那内部状态就是比如说我直接在Manager直接声明一个String变量。
private String title = "部门经理";
这个时候,不论外部怎么传递department或者reportContent,Manager的title是不变的,它不会随着的外部状态而变化。title永远都是部门经理。
5.组合模式
-
定义:将对象组合成树形结构以表示“部分 - 整体”的层次结构。组合模式使客户端对单个对象和组合对象保持一致的方式处理。比如说,我们有一个树形结构的菜单,菜单里面还有子菜单,在子菜单里面可能还有子菜单。
适用场景:希望客户端忽略组合对象与单个对象的差异时,处理一个树形结构。
优点:清楚的定义分层次的复杂对象,表示对象的全部或部分层次。让客户端忽略层次的差异,方便对整个层次结构进行控制。同时简化客户端代码。符合开闭原则。
缺点:限制类型时会较会复杂。使设计变的更加抽象。
相关设计模式:访问者模式(来访问组合模式的递归结构)。
代码举例:
老样子,举例一个业务场景,拿慕课网来说,这里有很多课程,也有课程目录,课程有名称和价格,例如Java课程,那这个课程就属于Java目录下,Java目录下有很多Java相关的课程,Python也一样。如果使课程的目录和课程继承同一个抽象类,例如目录组件,那么就可以把课程本身,还有由课程组合成的课程目录视为同一类对象进行操作,但是在操作上还会有一些差别,具体的差别在定制化处理。
//组合模式抽象类
public abstract class CatalogComponent {
public void add(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持添加操作");
}
public void remove(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持删除操作");
}
public String getName(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持获取名称操作");
}
public double getPrice(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持获取价格操作");
}
public void print(){
throw new UnsupportedOperationException("不支持打印操作");
}
}
//课程类
public class Course extends CatalogComponent {
private String name;
private double price;
public Course(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String getName(CatalogComponent catalogComponent) {
return this.name;
}
@Override
public double getPrice(CatalogComponent catalogComponent) {
return this.price;
}
@Override
public void print() {
System.out.println("Course name:" + name + "price:" + price);
}
}
//目录类
public class CourseCatalog extends CatalogComponent {
private List items = new ArrayList<>();
private String name;
public CourseCatalog(String name) {
this.name = name;
}
@Override
public void add(CatalogComponent catalogComponent) {
items.add(catalogComponent);
}
@Override
public void remove(CatalogComponent catalogComponent) {
items.remove(catalogComponent);
}
@Override
public void print() {
System.out.println(this.name);
for (CatalogComponent catalogComponent : items){
System.out.print(" ");
catalogComponent.print();
}
}
public String getName() {
return this.name;
}
}
//测试类
public class Test {
public static void main(String[] args) {
CatalogComponent linuxCourse = new Course("Linux课程", 11);
CatalogComponent windowsCourse = new Course("Windows课程", 10);
CatalogComponent javaCourseCatalog = new CourseCatalog("Java课程目录");
CatalogComponent mallCourse1 = new Course("Java电商课程1期", 55);
CatalogComponent mallCourse2 = new Course("Java电商课程2期", 66);
CatalogComponent designPattern = new Course("Java设计模式", 77);
javaCourseCatalog.add(mallCourse1);
javaCourseCatalog.add(mallCourse2);
javaCourseCatalog.add(designPattern) ;
//主目录
CatalogComponent imoocMainCourseCatalog = new CourseCatalog("慕课网课程主目录");
imoocMainCourseCatalog.add(linuxCourse);
imoocMainCourseCatalog.add(windowsCourse);
imoocMainCourseCatalog.add(javaCourseCatalog);
imoocMainCourseCatalog.print();
}
}
从运行结果我们也可以看到,我们new了一个主目录然后分别添加1个二级目录和2个课程,以输出前面空格来代表层级,在Java目录下面又有3个Java课程,这里从UML也可以看出CatalogComponent和CatalogComponent形成了组合关系。但是这里就会体现组合设计模式的缺点了,yejiushi也就是如果说要动态的对类型进行限制,会使业务逻辑比较复杂,例如说现在先Java课程目录本身是二级目录,慕课网目录是一级目录,对于空格来说,二级目录是需要打印2个的,从而区分从属关系,对于这里就要进行动态的类型判断了。也就是说使用组合设计模式,我们就要对抽象组件的设计多花点心思,而且还有缺点目录和课程哪些符合业务逻辑的重写,哪些不符合。
接着,我们现在还要改代码,其实很简单,只要添加1个层级就好了
public class CourseCatalog extends CatalogComponent {
private List items = new ArrayList<>();
private String name;
//添加层级
private Integer level;
......
@Override
public void print() {
System.out.println(this.name);
for (CatalogComponent catalogComponent : items){
//进行输出
if (this.level != null){
for (int i = 0;i
6.桥接模式
定义:将抽象部分与它的具体实现部分分离,使它们都可以独立地变化。通过组合的方式建立两个类之间联系,而不是继承。
适用场景:抽象和具体实现之间增加更多的灵活性,适用桥接模式就可以避免这两个层次之间建立静态的继承关系,通过桥接模式建立一层关联关系,另外抽象部分和具体的实现部分都可以以继承的关系独立扩展,互不影响。就可以将抽象化的子类的对象和一个具体实现化的对象进行组合。一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。还有不希望使用继承,或因为多层继承导致系统类的个数剧增。
优点:分离抽象部分及其具体实现部分。提高了系统的可扩展性。
缺点:增加了系统的理解和设计难度,由于类之间的关系建立了抽象层,要求编程的时候,一开始就要对抽象层进行设计编程。需要正确的识别出系统中两个独立变化的维度。
相关设计模式:组合模式(更强调部分和整体间的组合),桥接模式强调平行级别不同类的集合。还有就是适配器模式,这两个设计模式都是为了两个东西配合合作,适配器改变已有的接口,让他们之间可以相互配合,而qia桥接是分离抽象和具体的实现类,目的是分离。
代码举例:
老样子举个例子,在中国有很多银行,农业(ABC)和工商银行(ICBC),然后我们就有自己的账号,关于存蓄账号分为定期账号和活期账号。定期可以存3个月或者1年,银行还会给利息,利息比活期账号利息高很多。这里面分2大块,银行和账号。·
//定义账号接口
public interface Account {
Account openAccount();
//查看账户类型
void showAccount();
}
//定期账号
public class DepositAccount implements Account{
@Override
public Account openAccount() {
System.out.println("打开定期账号");
return new DepositAccount();
}
@Override
public void showAccount() {
System.out.println("这是一个定期账号");
}
}
//活期账号
public class SavingAccount implements Account{
@Override
public Account openAccount() {
System.out.println("打开活期账号");
return new SavingAccount();
}
@Override
public void showAccount() {
System.out.println("这是一个活期账号");
}
}
//银行抽象类
public abstract class Bank {
protected Account account;
public Bank(Account account){
this.account = account;
}
abstract Account openAccount();
}
//农业银行
public class ABCBank extends Bank{
public ABCBank(Account account) {
super(account);
}
@Override
Account openAccount() {
System.out.println("打开中国农业银行账号");
//这里要注意委托实现
account.openAccount();
return account;
}
}
//工商银行
public class ICBCBank extends Bank {
public ICBCBank(Account account) {
super(account);
}
@Override
Account openAccount() {
System.out.println("打开中国工商银行账号");
//这里要注意委托实现
account.openAccount();
return account;
}
}
首先我们创建了Account,它是这个桥的实现接口,左侧是实现层,右侧是抽象层,桥接模式最重要的就是桥的左侧和右侧划分清楚,然后在Bank抽象类里持有Account接口的引用,这就是桥接模式的核心,通过组合的方式,底下的都是具体的类实现。而且可以一直扩展,这就是桥接模式的精华所在。
public class Test {
public static void main(String[] args) {
Bank icbcBank = new ICBCBank(new DepositAccount());
Account icbcAccount = icbcBank.openAccount();
icbcAccount.showAccount();
Bank abcBank = new ICBCBank(new SavingAccount());
Account abcAccount = abcBank.openAccount();
abcAccount.showAccount();
}
}
7.代理模式
定义:为其它对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。其实就跟租房子是一样的,假设找中介租房子,然后找全托管的房子,最后出租出来的房子是房东,房东是目标对象,合同朝你,水电费结算等等都是代理类来做,代理类就是中介,但是我们可以直接和代理类也就是中介签合同,不需要和房东直接接触。
优点:代理模式能将代理对象与真实被调用的对象分离,一定程度上降低了系统的耦合度m,扩展性好,保护目标对象,也增强目标对象。
缺点:代理模式会造成系统设计中类的数目增加。在客户端和目标对象增加了一个代理对象,会造成请求速度变慢,也增加了系统的复杂度。
扩展:静态代理。动态代理(Jdk中的动态代理只能对实现的接口的类生成代理,并不能具体的针对实现类,动态代理无法代理类,但是可以代理接口)。CGLib代理(是可以代理类的,它是针对类实现进行代理 ,如果代理一个类,CGLib会生成一个被代理类的子类,覆盖其中的方法。通过继承)。
相关设计模式:装饰者模式(实现上比较相似,但是目的不同,装饰者是给对象加上行为,代理模式是控制访问,更加注重设置代理人的方式来增加目标对象)。适配器模式(它主要考虑对象的接口,而代理模式是不能改变所代理的接口)。
代码举例:
动态代理
从UML图可以看出代理类与实现类都是继承了抽象类,这样的好处就是可以有一样的方法。
//接口
public interface Subject {
void visit();
}
//真实类
public class RealSubject implements Subject{
private String name = "juju";
@Override
public void visit() {
System.out.println(name);
}
}
//代理类
public class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject){
this.subject =subject;
}
@Override
public void visit() {
subject.visit();
}
}
//测试
public class Test {
public static void main(String[] args) {
ProxySubject proxySubject = new ProxySubject(new RealSubject());
proxySubject.visit();
}
}
从上面代码可以看出,代理类接收一个Subject对象,任何实现该接口的真实类,都可以通过这个代理类进行代理,增加了通用性,但是也有一个缺点,就是每一个代理类都必须要实现真是类的接口,这样会造成后期的臃肿。
动态代理
接口和真实类还是和静态代理一样,然后我们在创建一个DynamicProxy来进行动态代理来继承InvocationHandler,并重写invoke()
方法。然后进行测试。
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object,args);
return result;
}
}
//测试类
public class Test {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
DynamicProxy dynamicProxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader,new Class[]{Subject.class},dynamicProxy);
subject.visit();
}
}
这里创建动态对象通过Proxy.newProxyInstance()
来进行创建,第一个参数为表示当前使用到的appClassloader,第二个为目标对象实现的一组接口,第三个为表示当前的InvocationHandler实现实例对象。这里的动态对象创建是通过Jdk来实现的,当然还有其他通过非Jdk来实现的方法。
参考
- Java设计模式之代理模式
- Java设计模式精讲 Debug方式+内存分析