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

*///:~

目录
相关文章
|
22天前
|
Java
【Java集合类面试二十八】、说一说TreeSet和HashSet的区别
HashSet基于哈希表实现,无序且可以有一个null元素;TreeSet基于红黑树实现,支持排序,不允许null元素。
|
14天前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
42 0
|
2天前
|
Java
java的类详解
在 Java 中,类是面向对象编程的核心概念,用于定义具有相似特性和行为的对象模板。以下是类的关键特性:唯一且遵循命名规则的类名;描述对象状态的私有属性;描述对象行为的方法,包括实例方法和静态方法;用于初始化对象的构造方法;通过封装保护内部属性;通过继承扩展其他类的功能;以及通过多态增强代码灵活性。下面是一个简单的 `Person` 类示例,展示了属性、构造方法、getter 和 setter 方法及行为方法的使用。
|
6天前
|
Java API 开发者
【Java字节码操控新篇章】JDK 22类文件API预览:解锁Java底层的无限可能!
【9月更文挑战第6天】JDK 22的类文件API为Java开发者们打开了一扇通往Java底层世界的大门。通过这个API,我们可以更加深入地理解Java程序的工作原理,实现更加灵活和强大的功能。虽然目前它还处于预览版阶段,但我们已经可以预见其在未来Java开发中的重要地位。让我们共同期待Java字节码操控新篇章的到来!
|
4天前
|
Java
Java 对象和类
在Java中,**类**(Class)和**对象**(Object)是面向对象编程的基础。类是创建对象的模板,定义了属性和方法;对象是类的实例,通过`new`关键字创建,具有类定义的属性和行为。例如,`Animal`类定义了`name`和`age`属性及`eat()`、`sleep()`方法;通过`new Animal()`创建的`myAnimal`对象即可调用这些方法。面向对象编程通过类和对象模拟现实世界的实体及其关系,实现问题的结构化解决。
|
4天前
|
Java API 开发者
【Java字节码的掌控者】JDK 22类文件API:解锁Java深层次的奥秘,赋能开发者无限可能!
【9月更文挑战第8天】JDK 22类文件API的引入,为Java开发者们打开了一扇通往Java字节码操控新世界的大门。通过这个API,我们可以更加深入地理解Java程序的底层行为,实现更加高效、可靠和创新的Java应用。虽然目前它还处于预览版阶段,但我们已经可以预见其在未来Java开发中的重要地位。让我们共同期待Java字节码操控新篇章的到来,并积极探索类文件API带来的无限可能!
|
15天前
|
机器学习/深度学习 人工智能 算法
探索人工智能在医疗诊断中的应用与挑战Java编程中的对象和类:基础与实践
【8月更文挑战第27天】随着人工智能(AI)技术的飞速发展,其在医疗领域的应用日益广泛。本文深入探讨了AI技术在医疗诊断中的具体应用案例,包括图像识别、疾病预测和药物研发等方面,并分析了当前面临的主要挑战,如数据隐私、算法偏见和法规限制等。文章旨在为读者提供一个全面的视角,理解AI在改善医疗服务质量方面的潜力及其局限性。
|
16天前
|
Java Spring 容器
Java获取接口的所有实现类方法
这篇文章介绍了在Java中获取接口所有实现类的方法,包括使用JDK的ServiceLoader(SPI机制)和Spring Boot中的@Autowired自动注入及ApplicationContextAware接口两种方式。
37 1
|
19天前
|
存储 Java 索引
如何在 Java 中创建类对象的 Arraylist?
【8月更文挑战第23天】
25 1
|
22天前
|
存储 Java
【Java集合类面试二十九】、说一说HashSet的底层结构
HashSet的底层结构是基于HashMap实现的,使用一个初始容量为16和负载因子为0.75的HashMap,其中HashSet元素作为HashMap的key,而value是一个静态的PRESENT对象。