多例模式 == 枚举 ? -- 2022-02-17

哈喽,我是指北君。

“单例模式会吗?我们写道单例模式吧”。相信大家对这句话应该很熟悉,这是面试官的高频语句,指北君相信大家应该也都会,所以今天不讲单例,而是讲”多例”。多例?咋没怎么听过?没听过没关系,但你肯定用过枚举,枚举的主要作用是定义有限个对象的一种结构(多例设计),其就属于多例设计,其结构比多例结构更简单。所以我们接下来看看吧。


1 枚举的基本定义

从jdk1.5之后程序之中提供了enum的关键字,此关键字可以实现枚举的定义。

范例:

1
2
3
1
2
3
1
2
3
public enum Color {
    RED,GREEN,BLUE;  //实例化对象
}
1
2
3
4
5
6
public class Test {
    public static void main(String[] args) {
        Color c = Color.RED;      //获取实例化对象
        System.out.println(c);
    }
}

输出:RED

如果此时采用多例设计模式来进行设计,那么需要编写很多的程序代码,这样对于开发的复杂度是比较高的,因为里面毕竟牵扯到构造方法的私有化以及静态方法。多例设计与枚举设计虽然可以实现相同的功能,但是使用枚举可以在程序编译时就能判断所使用的实例化对象是否存在。

在进行枚举处理的时候还可以利用values()方法获取所有的枚举对象进行输出。

范例:获取所有的枚举对象:

1
2
3
1
2
3
1
2
3
public enum Color {
    RED,GREEN,BLUE;  //实例化对象
}
1
2
3
4
5
6
7
public class Test {
    public static void main(String[] args) {
        for(Color c :Color.values()){
            System.out.println(c);
        }
    }
}

输出:RED GREEN BLUE

如果此时同样的功能需要通过多例设计来解决的话,那么就需要使对象数组了。从jdk1.5追加了枚举结构之后,就可以在switch之中进行枚举项的判断。

范例:观察枚举与switch处理:

1
2
3
1
2
3
1
2
3
public enum Color {
    RED,GREEN,BLUE;  //实例化对象
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test {
    public static void main(String[] args) {
        Color c = Color.RED;
        switch (c){
            case RED :
                System.out.println("红色");
                break;
            case GREEN :
                System.out.println("绿色");
                break;
            case BLUE :
                System.out.println("蓝色");
                break;
        }
    }
}

输出:RED

多例上是无法实现这种与switch直接连接的,多例要想实现它就需要编写大量的if判断了。


2 Enum类

严格意义上来讲枚举并不属于一种新的结构,它的本质相当于一个类,但是这个类默认会继承Enum类。

类的基本定义:

1
public abstract class Enum<E extends Enum<E>>  entends Object implements Comparable<E>,Serializable

现在定义的枚举类的类型就是Enum中所使用的E

面试题:请解释enum与Enum的区别

enum:是从jdk1.5之后提供的一个关键字,用于定义枚举类。

Enum:是一个抽象类,所以使用enum关键字定义的类就默认继承了此类。


3 枚举结构定义

枚举属于一种多例设计模式,那么既然是多例设计模式,那么在一个类之中可以定义的结构是非常多的:列如:构造方法、普通方法、属性等,那么这些内容在枚举类中依然可以直接定义,但是需要注意的是:枚举类中定义的构造方法不能够采用非私有化定义(public 无法使用)

范例:在枚举类中定义其他结构:

1
2
3
4
5
6
7
8
9
10
11
public enum Color {
    RED("红色"),GREEN("绿色"),BLUE("蓝色");  //枚举对象一定要写在首行(多例设计里面的每个实例都是static final的常量,所以要大写)
    private String title;
    
    private Color(String title){
        this.title = title;
    }
    public String toString(){
        return this.title;
    }
}
1
2
3
4
5
6
7
public class Test {
    public static void main(String[] args) {
        for(Color c : Color.values()){
            System.out.println(c.ordinal()+"-"+c.name()+"-"+c.toString());
        }
    }
}

输出:0-RED-红色 1-GREEN-绿色 2-BLUE-蓝色

本程序在简化程度上一定要远远高于多例设计模式。除了这种基本的结构之外,在枚举类中也可以实现接口的继承。

范例:让枚举实现接口:

1
2
3
public interface IMessage {
    public String getMessage();
}
1
2
3
4
5
6
public class Test {
    public static void main(String[] args) {
        IMessage msg = Color.RED;
        System.out.println(msg.getMessage());
    }
}

输出:红色

在枚举类里面最有意思的是它直接定义抽象方法,并且要求每一个枚举对象都要独立复写该抽象方法。

范例:让枚举实现抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public enum Color extends SomeAbstractClass{
    RED("红色"){
        @Override
        public String getMessage() {
            return this.toString();
        }
    },GREEN("绿色"){
        @Override
        public String getMessage() {
            return this.toString();
        }
    },BLUE("蓝色"){
        @Override
        public String getMessage() {
            return this.toString();
        }
    };  //枚举对象一定要写在首行(多例设计里面的每个实例都是static final的常量,所以要大写)
    private String title;
 
    private Color(String title){
        this.title = title;
    }
    public String toString(){
        return this.title;
    }
    public abstract String getMessage();
}
1
2
3
4
5
public class Test {
    public static void main(String[] args) {
        System.out.println(Color.RED.getMessage());
    }
}

输出:红色

看了之后只有一个感觉,麻烦,所以这个一般不用。


4 枚举的实例应用

1
2
3
4
5
6
7
8
9
10
public enum Sex {
    MALE("男"),FEMALE("女");
    private String title;
    private Sex(String title){
        this.title = title;
    }
    public String toString(){
        return this.title;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Person {
    private String name;
    private int age;
    private Sex sex;
    public Person(String name,int age,Sex sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    public String toString(){
        return "姓名:" + this.name + "、年级:" + this.age + "、性别:" + this.sex;
    }
}
1
2
3
4
5
public class Test {
    public static void main(String[] args) {
        System.out.println(new Person("张三",20,Sex.MALE));
    }
}

输出:姓名:张三、年级:20、性别:男


5 小节

今天指北君主要介绍了枚举,这个也是大家平时在工作中使用的很频繁的一个特殊类,它是Java 5中新增特性的一部分,它是一种特殊的数据类型,之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。

我是指北君,操千曲而后晓声,观千剑而后识器。感谢各位人才的:点赞、收藏和评论,我们下期更精彩!

Java Geek Tech wechat
欢迎订阅 Java 技术指北,这里分享关于 Java 的一切。