重温经典《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

*///:~

目录
相关文章
|
25天前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
44 8
|
26天前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
57 1
|
1月前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
63 17
|
1月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
113 4
|
1月前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
58 2
|
1月前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
50 4
|
1月前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
51 3
|
1月前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
44 5
|
1月前
|
Java API Maven
如何使用 Java 字节码工具检查类文件的完整性
本文介绍如何利用Java字节码工具来检测类文件的完整性和有效性,确保类文件未被篡改或损坏,适用于开发和维护阶段的代码质量控制。
76 5