目录
本笔记参考自: 《On Java 中文版》
常量特定方法
在Java中,我们可以通过为每个枚举实例编写不同的方法,来赋予它们不同的行为。一个方式是在枚举类型中定义抽象方法,并在枚举实例中实现它:
【例子:为枚举实例编写方法】
import java.text.DateFormat;
import java.util.Date;
public enum ConstantSpecificMethod {
DATE_TIME {
@Override
String getInfo() {
return DateFormat.getDateInstance()
.format(new Date());
}
},
CLASSPATH {
@Override
String getInfo() {// getenv()方法用于获取指定环境变量的值
return System.getenv("CLASSPATH");
}
},
VERSION {
@Override
String getInfo() { // 获取由输入指定的属性
return System.getProperty("java.version");
}
};
abstract String getInfo();
public static void main(String[] args) {
for (ConstantSpecificMethod csm : values())
System.out.println(csm.getInfo());
}
}
程序执行的结果是:
在这个例子中,我们通过关联的枚举实例来调用对应的方法,这通常被称为表驱动模式。
这里需要复习一点:在面向对象的编程中,不同的行为是和不同的类相关联的。而上述枚举的每个实例都拥有各自不同的行为,这就表明每个实例都相当于不同的类型(体现了多态)。它们的共同点在于它们的基类ConstantSpecificMethod。
但这并不意味着枚举实例能够等价于普通的类:
【例子:枚举实例和类之间的不同点】
enum LikeClasses {
A {
@Override
void behavior() {
System.out.println("A");
}
},
B {
@Override
void behavior() {
System.out.println("B");
}
},
C {
@Override
void behavior() {
System.out.println("C");
}
};
abstract void behavior();
}
public class NotClasses {
// void f1(LikeClasses.A instance) {
// } // 不可行的操作
}
编译器并不允许f1()的操作:将枚举实例作为类的类型进行使用。为了解释这一点,可以对程序进行反编译(javap -c LikeClasses):
反编译告诉我们,每个枚举元素都是LikeClasses的一个static final实例。实例无法作为类型进行使用。
除此之外,不同于内部类,因为枚举实例是静态的,所以我们无法通过外部类LikeClasses直接访问其内部的枚举实例(具体而言,我们无法在非静态域中访问外部类的静态成员)。
(与匿名内部类相比,常量特定方法要显得更加简洁。)
除此之外,常量特定方法也支持重写:
【例子:重写常量特定方法】
public enum OverrideConstantSpecific {
NUT, BOLT,
WASHER {
@Override
public void f() {
System.out.println("重写后的f()方法");
}
};
void f() {
System.out.println("默认的f()方法");
}
public static void main(String[] args) {
for (OverrideConstantSpecific ocs : values()) {
System.out.print(ocs + ": ");
ocs.f();
}
}
}
程序执行的结果是:
这些特性使得我们在通常情况下,可以将枚举作为类来使用。
职责链模式的枚举实现
||| 职责链模式:先创建一批用于解决目标问题的不同方法,并将它们链式排列。当一个请求到达时,它会顺着这条“链”向下走,直到遇到可以解决当前请求的方法。
下面的例子描述了一个邮局模型:使用常规方法处理信件,当前方法不可行时,尝试其他方法,直到无法处理该信件为止(称为“死信”)。
可以将每种处理方法视作一种策略,策略的列表组成了一条职责链。
【例子:邮局模型】
import onjava.Enums;
import java.util.Iterator;
class Mail {
enum GeneralDelivery {YES, NO1, NO2, NO3, NO4, NO5} // 是否使用常规方式处理
enum Scannability {UNSCANNABLE, YES1, YES2, YES3, YES4} // 是否可以扫描
enum Readability {ILLEGIBLE, YES1, YES2, YES3, YES4} // 是否可读
enum Address {INCORRECT, OK1, OK2, OK3, OK4, OK5, OK6}
enum ReturnAddress {MISSING, OK1, OK2, OK3, OK4, OK5}
// 创建枚举变量
GeneralDelivery generalDelivery;
Scannability scannability;
Readability readability;
Address address;
ReturnAddress returnAddress;
static long counter = 0;
long id = counter++;
@Override
public String toString() {
return "邮件" + id;
}
public String details() {
return toString() +
",一般交付:" + generalDelivery + ",地址是否可以扫描:" + scannability +
"\n地址是否可读:" + readability + ",目标地址:" + address +
"\n返还地址:" + returnAddress;
}
// 用于生成测试邮件:
// (Enums类可见笔记 进阶1-1)
public static Mail randomMail() {
Mail m = new Mail();
// 为枚举实例随机赋值:
m.generalDelivery =
Enums.random(GeneralDelivery.class);
m.scannability =
Enums.random(Scannability.class);
m.readability =
Enums.random(Readability.class);
m.address =
Enums.random(Address.class);
m.returnAddress =
Enums.random(ReturnAddress.class);
return m;
}
// count无需修改,可以使用final
public static Iterable<Mail> generator(final int count) {
return new Iterable<Mail>() {
int n = count;
@Override
public Iterator<Mail> iterator() {
return new Iterator<Mail>() {
@Override
public boolean hasNext() {
return n-- > 0;
}
@Override
public Mail next() {
return randomMail();
}
};
}
};
}
}
public class PostOffice {
// 使用职责链模式:
enum MailHandler {
GENERAL_DELIVERY {
@Override