[7]复用类0X02
2016-07-26 10:58
302 查看
代理
所谓代理,并不是java直接提供支持的某个语法或特性,而是组合和继承的”中庸之道”。下面我们上代码来演示这种情况:
package me.funnyzhao.ship; /** * 太空船控制模块 * @author dell */ public class SpaceShipControls { void up(int velocity){} void down(int velocity){} void left(int velocity){} void right(int velocity){} void forward(int velocity){} void back(int velocity){} void turboBoost(){} }
一种构造太空船的方式是继承:
package me.funnyzhao.ship; //构造太空船的一种方式 继承 public class SpaceShip extends SpaceShipControls { private String name; public SpaceShip(String name){ this.name=name; } @Override public String toString() { return name; } public static void main(String[] args) { SpaceShip p=new SpaceShip("NSEA Protecor"); p.forward(100); } }
咱仔细观察代码,就会发现,上面这种方式并不合理,因为控制模块只是太空船的一部分而已。那更好的方式是什么?看下面的代码:
package me.funnyzhao.ship; /** * 使用代理的方式 * @author dell * */ public class SpaceShipDelegation { private String name; private SpaceShipControls controls= new SpaceShipControls(); public SpaceShipDelegation(String name){ this.name=name; } //代理方法 public void back(int velocity){ controls.back(velocity); } public void forward(int velocity){ controls.forward(velocity); } public void down(int velocity){ controls.down(velocity); } public void up(int velocity){ controls.up(velocity); } public void left(int velocity){ controls.left(velocity); } public void right(int velocity){ controls.right(velocity); } public void turboBoost(){ controls.turboBoost(); } public static void main(String[] args) { SpaceShipDelegation ssd=new SpaceShipDelegation("NF"); ssd.forward(100); } }
这就是使用代理的方式,可以发现,代理更像是多了一层的封装,使得我们对对象的方法有更多的灵活选择。
结合使用组合和继承
使用组合和继承构建更复杂的类,类的构造器也可以很清晰的分离:package me.funnyzhao.resuing; //写个同时使用组合和继承的程序 class Plate{ public Plate(int i) { System.out.println("Palate Cr"); } } class DinnerPlate extends Plate{ public DinnerPlate(int i) { super(i); System.out.println("DinnerPlate Cr"); } } class Utensil{ public Utensil(int i) { System.out.println("Utensil Cr"); } } class Spoon extends Utensil{ public Spoon(int i){ super(i); System.out.println("Spoon Cr"); } } class Fork extends Utensil{ public Fork(int i){ super(i); System.out.println("Fork Cr"); } } class Knife extends Utensil{ public Knife(int i) { super(i); System.out.println("Knife Cr"); } } class Custom{ public Custom(int i) { System.out.println("Custom Cr"); } } public class PlaceSetting extends Custom{ //组合 private DinnerPlate dp; private Spoon spn; private Fork fok; private Knife knf; public PlaceSetting(int i) { //编译器会强制你去初始化基类 super(i+1); //但是并不要求你必须把成员对象也初始化 dp=new DinnerPlate(i+2); spn=new Spoon(i+3); fok=new Fork(i+4); knf=new Knife(i+5); System.out.println("PlaceSetting Cr"); } public static void main(String[] args) { PlaceSetting x=new PlaceSetting(9); } } /*output: Custom Cr Palate Cr DinnerPlate Cr Utensil Cr Spoon Cr Utensil Cr Fork Cr Utensil Cr Knife Cr PlaceSetting Cr */
确保正确清理
在java中,由于垃圾回收机制的作用,我们可以不用关心如何、何时去释放对象的内存。但在有些时候,某个类可能在其生命周期内要执行一些必需的清理活动(一般根据业务逻辑或者开发的框架层来定)。
因为我们并不能准确的知道垃圾回收器何时将会被调用,或者它是否将被调用,因此想让某个类清理一些东西,就必须显示的编写一个特殊的方法来做这件事,并且要确保客户端程序员知晓他们必须要调用这一方法。
清理动作最好置于finally子句之中,以防异常的出现
在下面的代码中,请注意对基类调用清理方法和成员对象清理方法的调用顺序,以防止某个子对象依赖于另一个子对象的情形发生。
package me.funnyzhao.resuing; class Shape{ Shape(int i){ System.out.println("Shap Cr"); } void dispose(){ System.out.println("Shape dispose"); } } class Circle extends Shape{ Circle(int i){ super(i); System.out.println("Drawing Circle"); } void dispose(){ System.out.println("Erasing Circle"); super.dispose(); } } class Triangle extends Shape{ Triangle(int i){ super(i); System.out.println("Drawing Triangle"); } void dispose(){ System.out.println("Erasing Triangle"); super.dispose(); } } class Line extends Shape{ private int start,end; Line(int start,int end){ super(start); this.start=start; this.end=end; System.out.println("Drawing Line:"+start+","+end); } void dispose(){ System.out.println("Erasing Line:"+start+","+end); super.dispose(); } } public class CADSystem extends Shape{ private Circle c; private Triangle t; private Line[] lines=new Line[3]; public CADSystem(int i){ super(i+1); for (int j = 0; j < lines.length; j++) { lines[j]=new Line(j,j*j); } c=new Circle(1); t=new Triangle(1); //结合的构造器 System.out.println("Combined Cr"); } public void dispose(){ //清理 System.out.println("CADSystem.dispose()"); t.dispose(); c.dispose(); for (int i = 0; i < lines.length; i++) { lines[i].dispose(); } super.dispose(); } public static void main(String[] args) { CADSystem x=new CADSystem(47); try { //捕获会发生异常的代码 } catch (Exception e) { }finally{ x.dispose(); } } } /*output: Shap Cr Shap Cr Drawing Line:0,0 Shap Cr Drawing Line:1,1 Shap Cr Drawing Line:2,4 Shap Cr Drawing Circle Shap Cr Drawing Triangle Combined Cr CADSystem.dispose() Erasing Triangle Shape dispose Erasing Circle Shape dispose Erasing Line:0,0 Shape dispose Erasing Line:1,1 Shape dispose Erasing Line:2,4 Shape dispose Shape dispose */
就像上面的代码一样:通常清理工作所采用的形式应该与C++编译器在其析构函数上所施加的形式相同:首先,执行类的所有特定的清理动作,其顺序同生成顺序相反(这就要求基类元素仍旧存活)。
–>下面我们看java编程思想中的总结:
许多情况下,清理并不是问题,仅需让垃圾回收器完成该动作就行。但当必须亲自处理清理时,就得多做努力并多加小心。因为,一旦涉及垃圾回收,能够信赖的事情就不会很多了。垃圾回收期可能永远也无法被调用,即使被调用,它也可能以任何它想要的顺序来回收对象。最好的办法是除了内存以外,不能依赖垃圾回收器去做任何事。如果需要进行清理,最好是编写你自己的清理方法,但不要使用finalize();
名称屏蔽
“名称屏蔽”这个词乍一看并不能从字面上理解是什么意思,那么我们先看书上怎么说:
如果java的基类拥有某个已被多次重载的方法名称,那么在导出类中重新定义该方法名称并不会屏蔽在基类中的任何版本。因此,无论是在该层或者它的基类中对方法进行定义,重载机制都可以正常工作。
上面的描述已经很清晰了,下面上代码:
package me.funnyzhao.resuing; class Homer{ char doh(char c){ System.out.println("doh(char)"); return 'd'; } float doh(float f){ System.out.println("doh(float)"); return 1.0f; } } class Milhouse{} class Bart extends Homer{ void doh(Milhouse m){ System.out.println("doh(Milhouse)"); } } public class Hide { public static void main(String[] args) { Bart b=new Bart(); b.doh('x'); b.doh(2.0f); b.doh(1); b.doh(new Milhouse()); } } /**output: doh(char) doh(float) doh(float) doh(Milhouse) */
可以看到,虽然在Bart中引入了一个新的重载方法,但是其基类的所有重载反法都可以调用,并没有覆盖。怎么解决无法覆盖(重写)基类方法呢?
javaSE5新增了@Override注解,它不是关键字,但是可以把它当做关键字来使用。当你想重写父类的某个方法时,它可以帮你在编译期鉴别是否重写了该方法而不是重载:
class Lisa extends Homer{ //像这样,@Override注解可以防止你在不想重载时而意外进行了重载 @Override void doh(Milhouse m){ System.out.println("doh(Milhouse)"); } }
相关文章推荐
- overload和override的区别
- 依附品牌做代理 把握创业新机遇
- 代理区独立模式的说明
- 深入理解C#中new、override、virtual关键字的区别
- 解析abstract与override究竟可不可以同时使用
- http代理相关知识分析
- 为MySQL安装配置代理工具Kingshard的基本教程
- JavaScript的事件代理和委托实例分析
- asp代理采集的核心函数代码
- PHP和JAVA中的重载(overload)和覆盖(override) 介绍
- C++中overload,override,overwrite的区别详细解析
- nginx 1.0.0配ngx_cache_purge实现高效的反向代理
- php使用curl通过代理获取数据的实现方法
- C# new和override的区别分析
- C#中Override关键字和New关键字的用法详解
- 浅谈Java反射与代理
- java实现动态代理方法浅析
- 用Python编写脚本使IE实现代理上网的教程
- 在python中的socket模块使用代理实例
- 仅用50行Python代码实现一个简单的代理服务器