重温经典《Thinking in java》第四版之第七章 复用类(四十)

简介: 重温经典《Thinking in java》第四版之第七章 复用类(四十)

7.3 代理

第三种关系称为代理,Java中并没有提供对它的直接支持。这是继承与组合之间的中庸之道。因为我们将一个成员对象置于所要构造的类中,就像组合一样,但与此同时我们在新类中暴露了该成员对象的所有方法,就像继承。例如,太空船需要一个控制模块:

publicclassSpaceShipControls { 
voidup(intvelocity) {} 
voiddown(intvelocity) {} 
voidleft(intvelocity) {} 
voidright(intvelocity) {} 
voidforward(intvelocity) {} 
voidback(intvelocity) {} 
voidturboBoost() {} 
}

构造太空船的一种方式是使用继承:

publicclassSpaceShipextendsSpaceShipControls { 
privateStringname; 
publicSpaceShip(Stringname) { this.name=name; } 
publicStringtoString() { returnname; } 
publicstaticvoidmain(String[] args) { 
SpaceShipprotector=newSpaceShip("NSEA Protector"); 
protector.forward(100); 
    } 
}

然后,SpaceShip并非真正的SpaceShipControls类型,即便你可以告诉SpaceShip向前运动(forward())。更准确地讲,SpaceShip包含SpaceShipControls,与此同时,SpaceShipControls的所有方法在SpaceShip中都暴露了出来。代理解决了此难题:

publicclassSpaceShipDelegation { 
privateStringname; 
privateSpaceShipControlscontrols=newSpaceShipControls(); 
publicSpaceShipDelegation(Stringname) { 
this.name=name; 
    } 
// Delegated methods: publicvoidback(intvelocity) { 
controls.back(velocity); 
    } 
publicvoiddown(intvelocity) { 
controls.down(velocity); 
    } 
publicvoidforward(intvelocity) { 
controls.forward(velocity); 
    } 
publicvoidleft(intvelocity) { 
controls.left(velocity); 
    } 
publicvoidright(intvelocity) { 
controls.right(velocity); 
    } 
publicvoidturboBoost() { 
controls.turboBoost(); 
    } 
publicvoidup(intvelocity) { 
controls.up(velocity); 
    } 
publicstaticvoidmain(String[] args) { 
SpaceShipDelegationprotector=newSpaceShipDelegation("NSEA Protector"); 
protector.forward(100); 
    } 
}

上面的形式看似是组合的一种,其实其要表达的意思远比组合要有深远意义。我们使用代理时可以拥有更多的控制力,新增一些我们自己的个性化逻辑。

 

7.4 结合使用组合和继承

同时使用组合和继承是很常见的事情。下例就展示了同时使用这两种技术,并配以必要的构造器初始化,来创建更加复杂的类:

importstaticnet.mindview.util.Print.*; 
classPlate { 
Plate(inti) { 
print("Plate constructor"); 
    } 
} 
classDinnerPlateextendsPlate { 
DinnerPlate(inti) { 
super(i); 
print("DinnerPlate constructor"); 
    } 
} 
classUtensil { 
Utensil(inti) { 
print("Utensil constructor"); 
    } 
} 
classSpoonextendsUtensil { 
Spoon(inti) { 
super(i); 
print("Spoon constructor"); 
    } 
} 
classForkextendsUtensil { 
Fork(inti) { 
super(i); 
print("Fork constructor"); 
    } 
} 
classKnifeextendsUtensil { 
Knife(inti) { 
super(i); 
print("Knife constructor"); 
    } 
} 
// A cultural way of doing something: classCustom { 
Custom(inti) { 
print("Custom constructor"); 
    } 
} 
publicclassPlaceSettingextendsCustom { 
privateSpoonsp; 
privateForkfrk; 
privateKnifekn; 
privateDinnerPlatepl; 
publicPlaceSetting(inti) { 
super(i+1); 
sp=newSpoon(i+2); 
frk=newFork(i+3); 
kn=newKnife(i+4); 
pl=newDinnerPlate(i+5); 
print("PlaceSetting constructor"); 
    } 
publicstaticvoidmain(String[] args) { 
PlaceSettingx=newPlaceSetting(9); 
    } 
}

/* Output:

Custom constructor

Utensil constructor

Spoon constructor

Utensil constructor

Fork constructor

Utensil constructor

Knife constructor

Plate constructor

DinnerPlate constructor

PlaceSetting constructor

*///:~

 

7.5 在组合与继承之间选择

组合和继承都允许在新的类中放置子对象,组合是显示地这样做,而继承则是隐式地做。

组合技术通常用于想在新类中使用现有类的功能而非它的接口这种形式。

继承技术是使用一个现有类,并开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。

 

7.6 protected关键字

现在我们已介绍完了继承,关键字protected最终具有了意义。在理想世界中,仅靠关键字private就已经足够了。但是实际项目中,经常会想要将某些事物尽可能对这个世界隐藏起来,但是允许导出类的成员访问它们。

关键字protected就是起这个作用的。它指明“就类用户而言,这是private的,但是对于任何继承于此类的导出来或者其他任何位于同一个包内的类来说,它确实可以访问的。”

尽管可以创建protected域,但是最好的方式还是将域保持为private;你应该一直保留更改底层实现的权利。下面就是一个通过protected方法来控制类的继承者的访问权限:

//: reusing/Orc.java // The protected keyword. importstaticnet.mindview.util.Print.*; 
classVillain { 
privateStringname; 
protectedvoidset(Stringnm) { name=nm; } 
publicVillain(Stringname) { this.name=name; } 
publicStringtoString() { 
return"I’m a Villain and my name is "+name; 
    } 
} 
publicclassOrcextendsVillain { 
privateintorcNumber; 
publicOrc(Stringname, intorcNumber) { 
super(name); 
this.orcNumber=orcNumber; 
    } 
publicvoidchange(Stringname, intorcNumber) { 
set(name); // Available because it’s protected this.orcNumber=orcNumber; 
    } 
publicStringtoString() { 
return"Orc "+orcNumber+": "+super.toString(); 
    } 
publicstaticvoidmain(String[] args) { 
Orcorc=newOrc("Limburger", 12); 
print(orc); 
orc.change("Bob", 19); 
print(orc); 
    } 
}

/* Output:

Orc 12: I’m a Villain and my name is Limburger

Orc 19: I’m a Villain and my name is Bob

*///:~

目录
相关文章
|
Java 编译器 API
Java 密封类:精细化控制继承关系
Java 密封类:精细化控制继承关系
594 83
|
IDE Java 数据挖掘
Java 基础类从入门到精通实操指南
这份指南专注于**Java 17+**的新特性和基础类库的现代化用法,涵盖开发环境配置、数据类型增强(如文本块)、字符串与集合处理进阶、异常改进(如密封类)、IO操作及实战案例。通过具体代码示例,如CSV数据分析工具,帮助开发者掌握高效编程技巧。同时提供性能优化建议和常用第三方库推荐,适合从入门到精通的Java学习者。资源链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
728 37
|
12月前
|
安全 Java 数据建模
Java记录类:简化数据载体的新选择
Java记录类:简化数据载体的新选择
568 101
|
12月前
|
安全 Java 开发者
Java记录类:简化数据载体的新方式
Java记录类:简化数据载体的新方式
451 100
|
安全 IDE Java
Java记录类型(Record):简化数据载体类
Java记录类型(Record):简化数据载体类
704 143
|
11月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
476 4
|
11月前
|
IDE JavaScript Java
在Java 11中,如何处理被弃用的类或接口?
在Java 11中,如何处理被弃用的类或接口?
444 5
|
11月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
566 5
|
11月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
543 1
|
11月前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
596 1