走到这一步,接下来该考虑一下设计方案剩下的部分了——在哪里使用类?既然归类到垃圾箱的办法非常不雅且过于暴露,为什么不隔离那个过程,把它隐藏到一个类里呢?这就是著名的“如果必须做不雅的事情,至少应将其本地化到一个类里”规则。看起来就象下面这样:

现在,只要一种新类型的Trash加入方法,对TrashSorter对象的初始化就必须变动。可以想象,TrashSorter类看起来应该象下面这个样子:

class TrashSorter extends Vector {

void sort(Trash t) { /* ... */ }

}

也就是说,TrashSorter是由一系列句柄构成的Vector(系列),而那些句柄指向的又是由Trash句柄构成的Vector;利用addElement(),可以安装新的TrashSorter,如下所示:

TrashSorter ts = new TrashSorter();

ts.addElement(new Vector());

但是现在,sort()却成为一个问题。用静态方式编码的方法如何应付一种新类型加入的事实呢?为解决这个问题,必须从sort()里将类型信息删除,使其需要做的所有事情就是调用一个通用方法,用它照料涉及类型处理的所有细节。这当然是对一个动态绑定方法进行描述的另一种方式。所以sort()会在序列中简单地遍历,并为每个Vector都调用一个动态绑定方法。由于这个方法的任务是收集它感兴趣的垃圾片,所以称之为grab(Trash)。结构现在变成了下面这样:

其中,TrashSorter需要调用每个grab()方法;然后根据当前Vector容纳的是什么类型,会获得一个不同的结果。也就是说,Vector必须留意自己容纳的类型。解决这个问题的传统方法是创建一个基础“Trash bin”(垃圾筒)类,并为希望容纳的每个不同的类型都继承一个新的衍生类。若java有一个参数化的类型机制,那就也许是最直接的方法。但对于这种机制应该为我们构建的各个类,我们不应该进行麻烦的手工编码,以后的“观察”方式提供了一种更好的编码方式。

OOP设计一条基本的准则是“为状态的变化使用数据成员,为行为的变化使用多性形”。对于容纳Paper(纸张)的Vector,以及容纳Glass(玻璃)的Vector,大家最开始或许会认为分别用于它们的grab()方法肯定会产生不同的行为。但具体如何却完全取决于类型,而不是其他什么东西。可将其解释成一种不同的状态,而且由于Java有一个类可表示类型(Class),所以可用它判断特定的Tbin要容纳什么类型的Trash。

用于Tbin的构建器要求我们为其传递自己选择的一个Class。这样做可告诉Vector它希望容纳的是什么类型。随后,grab()方法用Class BinType和RTTI来检查我们传递给它的Trash对象是否与它希望收集的类型相符。

下面列出完整的解决方案。设定为注释的编号(如*1*)便于大家对照程序后面列出的说明。

//: RecycleB.java

// Adding more objects to the recycling problem

package c16.recycleb;

import c16.trash.*;

import java.util.*;

// A vector that admits only the right type:

class Tbin extends Vector {

Class binType;

Tbin(Class binType) {

this.binType = binType;

}

boolean grab(Trash t) {

// Comparing class types:

if(t.getClass().equals(binType)) {

addElement(t);

return true; // Object grabbed

}

return false; // Object not grabbed

}

}

class TbinList extends Vector { //(*1*)

boolean sort(Trash t) {

Enumeration e = elements();

while(e.hasMoreElements()) {

Tbin bin = (Tbin)e.nextElement();

if(bin.grab(t)) return true;

}

return false; // bin not found for t

}

void sortBin(Tbin bin) { // (*2*)

Enumeration e = bin.elements();

while(e.hasMoreElements())

if(!sort((Trash)e.nextElement()))

System.out.println("Bin not found");

}

}

public class RecycleB {

static Tbin bin = new Tbin(Trash.class);

public static void main(String[] args) {

// Fill up the Trash bin:

ParseTrash.fillBin("Trash.dat", bin);

TbinList trashBins = new TbinList();

trashBins.addElement(

new Tbin(Aluminum.class));

trashBins.addElement(

new Tbin(Paper.class));

trashBins.addElement(

new Tbin(Glass.class));

// add one line here: (*3*)

trashBins.addElement(

new Tbin(Cardboard.class));

trashBins.sortBin(bin); // (*4*)

Enumeration e = trashBins.elements();

while(e.hasMoreElements()) {

Tbin b = (Tbin)e.nextElement();

Trash.sumValue(b);

}

Trash.sumValue(bin);

}

} ///:~

(1) TbinList容纳一系列Tbin句柄,所以在查找与我们传递给它的Trash对象相符的情况时,sort()能通过Tbin继承。

(2) sortBin()允许我们将一个完整的Tbin传递进去,而且它会在Tbin里遍历,挑选出每种Trash,并将其归类到特定的Tbin中。请注意这些代码的通用性:新类型加入时,它本身不需要任何改动。只要新类型加入(或发生其他事件)时大量代码都不需要变化,就表明我们设计的是一个容易扩展的系统。

(3) 现在可以体会添加新类型有多么容易了。为支持添加,只需要改动几行代码。如确实有必要,甚至可以进一步地改进设计,使更多的代码都保持“固定”。

(4) 一个方法调用使bin的内容归类到对应的、特定类型的垃圾筒里。

java中运用抽象_如何学会java中的抽象应用相关推荐

  1. canvas java 上传截图_在Vue项目中使用html2canvas生成页面截图并上传

    使用方法 项目中引入 npm install html2canvas html代码 //html代码 js代码 // 引入html2canvas import html2canvas from 'ht ...

  2. java 中的流_深入理解Java中的流(Stream)

    首先,流是什么? 流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以"流"的方式进行.设备可以是文件,网络,内存等. 流具有方向性,至于是输入 ...

  3. java 常量放在哪里_浅谈JAVA中字符串常量的储存位置

    在讲述这些之前我们需要一些预备知识: Java的内存结构我们可以通过两个方面去看待它. 从该角度看的话Java内存结构包含以下部分: 1.栈区:由编译器自动分配释放,具体方法执行结束后,系统自动释放J ...

  4. java a标签正则_正则表达式:java中婚配HTML中a标签中的中文字符

    正则表达式:java中匹配HTML中a标签中的中文字符 今天群里一位朋友问到了一个正则表达式的问题,有如下内容: 特432 453543 a1特123你好123吗? 特2 标签中的文字现在要匹配出内容 ...

  5. java 返回空数组_避免在Java中检查Null语句

    1.概述 通常,在Java代码中处理null变量.引用和集合很棘手.它们不仅难以识别,而且处理起来也很复杂.事实上,在编译时无法识别处理null的任何错误,会导致运行时NullPointerExcep ...

  6. java中的方法 net.中的函数_.Net转Java.01.从Main(main)函数说起

    在C#中,main函数的签名可以有四种 static void Main(string[] args) static void Main() static int Main(string[] args ...

  7. java栈 类 堆_详细介绍Java中的堆和栈

    栈与堆都是Java用来在RAM中寄存数据的中央.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. Java的堆是一个运转时数据区,类的对象从中分配空间.这些对象经过new.newar ...

  8. java 线程中创建线程_如何在Java 8中创建线程安全的ConcurrentHashSet?

    java 线程中创建线程 在JDK 8之前,还没有办法在Java中创建大型的线程安全的ConcurrentHashSet. java.util.concurrent包甚至没有一个名为Concurren ...

  9. java整数的因式分解_如何在Java中找到整数的质数-因式分解

    java整数的因式分解 编程课程中的常见家庭作业/任务之一是关于Prime Factorization. 要求您编写一个程序以找到给定整数的素因子 . 一个数字的素数因子是将精确地除以给定数字的所有素 ...

最新文章

  1. 华为静态、默认、备用路由配置
  2. 使用StarUML创建类图
  3. Fcrackzip——简介、安装、使用
  4. 一张图看懂阿里云网络产品[二] 专有网络VPC
  5. 向对象中添加数据_在RMarkdown编译HTML文件中添加数据下载按钮
  6. 如何在eclipse里使用git
  7. 忍者神龟java_忍者神龟-邪恶重生
  8. 解码隆基模式:光伏企业的百亿成长之路
  9. Matlab非线性拟合函数——nlinfit
  10. 线上电商运营流程绘制流程图分享
  11. C++fseek函数
  12. CanBus的数据帧的获取和初始解析
  13. 手机拍照及简单的图片压缩
  14. Centos隐藏桌面图标
  15. 将项目部署到云服务器上
  16. Unity——责任链模式(土味情话传递)
  17. 使用jdk查看jks文件信息
  18. 微信小程序云开发查询数据库结果为空
  19. k2p一直亮红灯搜不到信号_关于投屏搜索不到电视,分析思路
  20. 约瑟夫环问题(C语言循环链表)

热门文章

  1. 复仇者联盟与IntelliJ IDEA也很配哦
  2. 如何监控impala的数据_CDH秘籍(两):cloudera Manager存储监控数据
  3. python原始数据是什么_以python请求发送原始数据
  4. from torchvision import _C解决办法
  5. randaugment
  6. python边缘检测显示原图边缘
  7. `pydot` failed to call GraphViz.Please install GraphViz
  8. 应用程序无法正常启动(0xc000007b)。请单击“确定”关闭应用程序
  9. python 双边滤波与高斯滤波
  10. Cissp-【第3章 安全工程】-2021-2-20(248页-268页)