您的位置:首页 > 其它

[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)");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Override 代理