适配器模式的意:使用不同免费股票交易接口编程,接口的类所提供的服务为客户端提供其所希望的免费股票交易接口编程,接口;
--问题解决场景:在类A中实现了接口中的抽象方法,客户端B已经定义好了方法的调用,但是调用的方法与类A中的方法名不同,这时我们就需要适配器模式了;
--eg:类A实现了接口A1,类B实现了接口B1,这里C调用A和B希望A和B能提供相同方法的接口,这时我们需要使用适配器模式;
接口适配
接口适配简介
接口适配:
--问题场景:客户端需要调用客户端类接口中提供的requiredMethod()的方法,但是工具类中只提供了一个existMethod()方法,显然客户端接口与工具类中提供的方法名称不匹配;
--适配方案:创建一个适配器类,适配现有的代码工具类,该类实现客户端接口的requiredMethod()抽象方法,与客户端接口是实现关系,同时该实现类继承工具类,可以调用工具类中的方法,与工具类的关系是继承关系;
--方法委托:通过接口适配,就将客户端类的requiredMethod()方法委派给了existMethod()方法;
接口适配实例
接口适配需求:
--客户端提供接口:需要研发一种M1坦克,需要实现接口getCaliber()获取火炮口径,fire()开火,run()移动等方法;
--现有接口:现有的坦克有getGunCaliber()获取火炮口径,GunFire()火炮开火,Move()移动等方法;
--适配要求:写一个适配类,这个类实现Panzer接口,继承Tanker类,将Panzer接口的动作委托给Tanker类;
接口类:
[java]viewplaincopypackageshulianhadisplaytest;publicinterfacePanzer{publicdoublegetCaliber();publicvoidfire();publicvoidrun();}
实体类
[java]viewplaincopypackageshulianhadisplaytest;publicclassTanker{privatedoublecaliber=120;publicdoublegetGunCaliber(){returncaliber;}publicvoidgunFire(){Systeout.println('Fireinthehole!!!');}publicvoidmove(){Systeout.println('Movemove!!');}}
分析:
--名称不匹配:Tanker类中的方法可以执行Panzer接口中需要的动作,但是它们的方法名称不匹配;
--变量维护:如果创建一个M1A2SEP类,需要在类中维护一个Tank对象,在Panzer实现类中调用对应的Tank对象方法;
[java]viewplaincopypackageshulianhadisplaytest;publicclassM1A2SEPextendsTankerimplementsPanzer{@OverridepublicdoublegetCaliber(){returngetGunCaliber();}@Overridepublicvoidfire(){gunFire();}@Overridepublicvoidrun(){move();}}
接口适配总结:
--客户端接口存在:如果客户端接口中定义了客户端所期待的行为,可以运用适配器模式,适配器继承现有类,并实现客户端接口;
--客户端接口不存在:如果客户端没有定义接口,可以使用对象适配器,对象适配器相当于子类适配器;
对象适配
对象适配简介
类适配:上面的接口适配方式就是类适配,适配器类需要实现客户端接口,继承现有实体类;
对象适配:对象适配器采用了委派,并非是继承;创建一个对象适配器,继承客户端类,在类中维护一个现有类实例对象,满足客户端类需求方法;
--需要场景:如果适配的客户端方法没有被定义在接口中,就需要对象适配;
对象适配的方法:
--适配器类继承客户端类:对象适配的适配器类继承客户端类对象,适配器类的实例也是客户端类的实例,因为适配器类是客户端类的子类;
--适配器类使用现有类:适配器类中定义一个现有类对象作为成员变量,通过调用现有类对象中的方法来实现客户端类方法的需求;
对象适配实例
客户端类:现在有客户端类Panzer装甲车,提供获取火炮口径方法getCaliber(),移动方法run(),开火方法fire();
现有类:现有类Tank坦克,提供获取火炮口径方法getGunCaliber(),移动方法move(),开火方法gunFire();
客户端类代码:客户端类代码中没有指定建模所需的接口;
[java]viewplaincopypackageshulianhaadapter;publicclassPanzer{publicdoublegetCaliber(){return0;}publicvoidfire(){//TODO}publicvoidrun(){//TODO}}
现有类代码
[java]viewplaincopypackageshulianhaadapter;publicclassTank{privatedoublecaliber=120;publicdoublegetGunCaliber(){returncaliber;}publicvoidgunFire(){Systeout.println('Fireinthehole!!!');}publicvoidmove(){Systeout.println('MoveMove!!!');}}
UML:
适配器类:
[java]viewplaincopypackageshulianhaadapter;publicclassM1A2extendsPanzer{privateTanktank;publicM1A2(){tank=newTank();}@OverridepublicdoublegetCaliber(){returntangetGunCaliber();}@Overridepublicvoidfire(){super.fire();tangunFire();}@Overridepublicvoidrun(){super.run();tanmove();}}
脆弱的对象适配
对象适配比类适配要脆弱:
--没有规范接口:对象适配的类中没有规范的接口,如果客户端类出现了变化,运行时可能出现错误;
--客户端类不可预知:对象适配类继承客户端类,首先客户端类需要将方法和变量声明为protected,即使这样,这些类的方法也可能不符合子类意;
Jtable对数据适配
JTable适配数据方法:JTable类可以将实现了TableModel抽象类的数据显示到形界面中;
--数据不确定性:Java中的Swing提供了JTable控件用以显示列表,JTable不知道我们要显示什么数据;
--适配器:将数据交给JTable控件并显示出来,需要一个适配器,这些数据要经过一个适配器接口,这个接口是TableModel抽象类;
TableModel子类实现:
--抽象方法多:Jtable定义了许多抽象方法,其子类必须实现所有的抽象方法,这样会很麻烦;
--TableModel的桩:JDK中提供了另一个抽象类AbstractTableModel类,AbstractTableModel继承了TableModel类,并实现了绝大部分方法,我们可以定义一个类去继承AbstractTableModel类,并实现我们感兴趣的方法,不必实现所有的方法了;
--数据封装:创建一个类继承AbstractTableModel类,然后呢实现感兴趣的接口;
实例
实现过程:使用JTable绘制坦克相关数据,需要创建一个TankTableModel类继承AbstractTableModel类,然后将Tank类封装在TankTableModel中,当做其成员变量;
使用对象适配的原因:
--AbstractTableModel抽象类:该抽象类提供了适配器对象需要实现的接口(抽象方法),该抽象类又实现了客户端JTable类期待的接口,适配器对象必须继承抽象类;
--组合第三对象:适配器对象还需要重用第三个对象,重用对象的方法只能是继承和组合,Java是单继承机制,只能使用组合方式,即将第三个对象当做适配器类的成员变量;
UML:
Tank代码:
[java]viewplaincopypackageshulianhajtable;publicclassTank{privatedoublecaliber;privatedoublespeed;privateStringname;publicTank(doublecaliber,doublespeed,Stringnam{this.caliber=caliber;this.speed=speed;this.name=name;}publicdoublegetCaliber(){returncaliber;}publicdoublegetSpeed(){returnspeed;}publicStringgetName(){returnname;}}
[java]viewplaincopypackageshulianhajtable;importjavax.swintablAbstractTableModel;publicclassTankTableModelextendsAbstractTableModel{privateTanktanks[];privateStringnames[];publicTankTableModel(Tank[]tanks,String[]names){this.tanks=tanks;this.names=names;}@OverridepublicintgetRowCount(){returntanks.length;}@OverridepublicintgetColumnCount(){returnnames.length;}@OverridepublicStringgetColumnName(intcolum{returnnames[column];}@OverridepublicObjectgetValueAt(introwIndex,intcolumnIndex){switch(columnIndex){case0:returntanks[rowIndex].getName();case1:returnnewDouble(tanks[rowIndex].getCaliber());case2:returnnewDouble(tanks[rowIndex].getSpeed());default:returnnull;}}}
[java]viewplaincopypackageshulianhajtable;importjavawt.Component;importjavawt.Dimension;importjavawt.Font;importjavax.swinJFrame;importjavax.swinJScrollPane;importjavax.swinJTable;importjavax.swinUIManager;publicclassShowTanksData{publicstaticvoidmain(String[]args){setFrame();JTablejTable=newJTable(getTankTableModel());jTablsetRowHeight(3;JScrollPanepane=newJScrollPane(jTabl;pansetPreferredSize(newDimension(300,100));display(pane,'坦克数据');}privatestaticvoidsetFrame(){Fontfont=newFont('Dialog',Font.PLAIN,1;UIManager.put('Tablfont',font);UIManager.put('TableHeader.font',font);}privatestaticTankTableModelgetTankTableModel(){Tanktank1=newTank(120.0,50.0,'99式');Tanktank2=newTank(150.0,0,'KV');returnnewTankTableModel(newTank[]{tank1,tank2},newString[]{'名称','火炮口径','速度'});}privatestaticvoiddisplay(Componentcomponent,Stringtittl{JFrameframe=newJFrame(tittl;framgetContentPane().add(component);framsetDefaultCloseOperation(JFramEXIT_ON_CLOS;frampack();framsetVisible(tru;}}
效果:
识别适配器
MouseAdapter为MouseListener接口提供桩的实现;
在使用MouseAdapter的时候,就相当于使用了适配器:用户操作鼠标的时候,将swing组件接收到的鼠标操作适配给相应的动作处理类中,即将GUI时间适配给应用程序接口,使用了Swing适配类,将一个接口方法委派给一个类的方法去执行;
适配器模式总结
适配器总结:适配器模式可以重用一个现有类,满足客户端需求,将客户端的调用转化为现有方法的调用;
--类适配器:客户端的需求通过接口表达出来,可以创建一个实现了该接口的适配类,适配类同时还要继承现有类;
--对象适配:客户端没有指定接口,创建一个新适配器类,实现继承客户端类,在该类中维护一个现有类的实例对象作为成员变量;
JTable适配器模式:通过定义TableModel接口,JTable组件将客户端需要的表信息存储到自身中,通过自定义适配器对象,将任何数据适配到表中;
JTable不适用类适配原因:
--继承数量限制:JTable适配器需要继承AbstractTableModel类,这样就无法继承现有类,因为只能继承一个类;
--需要维护多个对象:JTable需要大量数据,一般是从多个对象中采集的;
设计适配器模式:当我们设计软件的时候,充分考虑程序的灵活性,JTable的设计就是一个很好的范例;
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点