欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单例设计模式、多例设计模式和枚举类型

程序员文章站 2024-03-26 09:27:53
...

一、单例设计模式

1.含义

一个类只能产生一个实例对象。

2.饿汉式实现方法

特点:不管是否使用单例对象,只要该类加载了,那么一定会自动创建一个公共的instance对象。

package com.xunpu.singleAndMulti;

//饿汉式
class Singleton1{
    //1.属性静态化、不可修改化
    // static :解决必须先创建对象后才可以为属性分配空间的问题
    //final :只能有一个实例化对象
    private final static Singleton1 instance=new Singleton1();
    //2.构造方法私有化,避免外界创建多个对象。
    private Singleton1(){

    }
    //2.获取对象用static修饰,静态方法,便于在不产生对象时调用。
    public static Singleton1 getInstance(){
        return instance;
    }
}
public class Singleton {
    public static void main(String[] args) {
        Singleton1 singleton1=Singleton1.getInstance();
        Singleton1 singleton2=Singleton1.getInstance();
        System.out.println(singleton1==singleton2);
    }


}

单例设计模式、多例设计模式和枚举类型

结果为true,说明这两个对象指向同一块内存空间,单例实现。

3.懒汉式实现方法

特点:当第一次使用Singleton对象的时候才会为其产生实例化对象的操作。

package com.xunpu.singleAndMulti;
//懒汉式
class Singleton2{
    //1.属性静态化,便于后面的获取单例对象的调用。
    private static Singleton2 instance = null;
    //2.构造方法私有化
    private Singleton2(){

    }
    //3.获取实例化对象方法静态化,便于再不产生对象的情况下调用。
    public static Singleton2 getInstance() {
        if (instance == null) {//此时还没有实例化
            instance = new Singleton2();
        }
        return instance;
    }
}
public class Singleton {
    public static void main(String[] args) {
        Singleton2 singleton1=Singleton2.getInstance();
        Singleton2 singleton2=Singleton2.getInstance();
        System.out.println(singleton1==singleton2);
    }


}

单例设计模式、多例设计模式和枚举类型

懒汉式会存在线程安全问题,而饿汉式不会存在。

改进的懒汉式(线程安全):

//3.懒汉式双重检查
class Singleton3{
    private static volatile Singleton3 instance;
    private Singleton3(){
        
    }
    public static Singleton3 getInstance(){
        if(instance==null){
            synchronized (Singleton3.class){
                if(instance==null) {
                    instance = new Singleton3();
                }
            }
        }
        return instance;
    }
}

懒汉式(双重检查):

/**
 * 懒汉式(双重检查)
 */
public class Singleton {
    private volatile static Singleton instance;//使用volaitle修饰,防止指令重排,对象一定是属性全部初始化后的对象。保证可见性。
    //构造方法私有化
    private Singleton(){

    }
    //外界调用静态方法实例化对象
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance==null){//再次判断是为了防止在此期间,其它线程已经创建好了对象。
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

有关单例的更好分析请参见:手写单例,不心慌。

二、多例设计模式

要描述一周的类,只有七个对象;要描述性别,只有两个对象。这些都是多例设计模式。多例只是比单例追加了更多个实例化对象而已。其实,多例就是多个单例对象。

package com.xunpu.singleAndMulti;

class Sex{
    private String str;
    //属性被final static修饰
    private final static int MALE=1;
    private final static int FEMALE=2;
    private final static Sex male=new Sex("男");
    private final static Sex female=new Sex("女");
    //构造方法私有化
    private Sex(String str){
        this.str=str;
    }
    //取得对象方法用static修饰
    public static Sex getInstance(int flag){
        switch (flag){
            case 1:
                return male;
            case 2:
                return female;
            default:
                return null;
        }
    }
}
public class MultiTest  {
    public static void main(String[] args) {
        Sex male=Sex.getInstance(1);
        Sex male2=Sex.getInstance(1);
        Sex female1=Sex.getInstance(2);
        Sex female2=Sex.getInstance(2);
        System.out.println(male==male2);
        System.out.println(female1==female2);
    }
}

单例设计模式、多例设计模式和枚举类型

多例设计模式现在已经被枚举所代替。

三、枚举类型(JDK1.5开始)

1.特点

它的实例个数是有限的,而且这些实例是枚举类的静态常量。

2.枚举类型的定义和方法

定义:

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

这说明Enum类是抽象类,<E extends Enum<E>>为泛型标记,表示Enum类拥有的静态变量也是Enum类型或者其子类型。

方法:

构造方法:
 protected Enum(String name, int ordinal)
其它方法:
public final String name();//返回当前枚举类型的名称
public final int ordinal();//返回当前枚举常量的序数
public final int compareTo(E o);//比较当前枚举常量与指定对象的顺序。
public final Class<E> getDeclaringClass();//返回表示当前枚举常量的枚举类型的Class对象
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name);//根据指定的枚举类型和名称返回相应的枚举常量实例。
public static Enum[] values();//以数组的形式返回该枚举类型的所有枚举常量实例。

3.自定义枚举类型

用户定义的枚举类只需要继承Enum类就行了。

//方式一:直接继承Enum类
public class Gender extends Enum{
    public static final Gender FEMALE;
    public static final Gender MALE;

    ......
}
//方式二:使用enum类型(简单)
public enum Gender{FEMALE,MALE}
package com.xupu;

public class GenderTest {
    //在内部定义Gender枚举类
    enum Gender{
        FEMALE,
        MALE
    }
    public static void main(String[] args) {
        //遍历Gender类的所有常量
        for(Gender g:Gender.values()){
            System.out.println(g.ordinal()+" "+g.name());
        }
        Gender g=Gender.FEMALE;
        switch (g){
            case FEMALE:
                System.out.println("女");
                break;
            case MALE:
                System.out.println("男");
                break;
            default:
                System.out.println("未知的性别");
        }
    }
}

单例设计模式、多例设计模式和枚举类型

由此可知,枚举类型默认从0开始。

4.自定义构造方法

在自定义的枚举类中也可以自定义构造方法和属性,这个方法必须是private修饰的。

package com.xupu;

public class GenderTest {
    //在内部定义Gender枚举类
    enum Gender{
        FEMALE("女性"),
        MALE("男性");
        private String des;
        //构造方法私有化
        private Gender(String des){
            this.des=des;
        }
        public String getDes(){
            return des;
        }
    }
    public static void main(String[] args) {
        //遍历Gender类的所有常量
        for(Gender g:Gender.values()){
            System.out.println(g.ordinal()+" "+g.name()+" "+g.getDes());
        }
        Gender g=Gender.FEMALE;
        System.out.println(g.getDes());
    }
}

单例设计模式、多例设计模式和枚举类型

FEMALE和MALE这两个常量通过Gender(String des)构造方法来创建。

在枚举类中声明多个枚举常量时,常量之间用","隔开,最后一个常量用";"结尾。

5.EnumSet类和EnumMap类

在Java API中,还为Enum类提供了两个适配器:

java.util.EnumSet类:把枚举类型转换为集合类型。它的静态的allOf()能把枚举类的所有常量实例存放在一个EnumSet集合中,然后返回这个集合。
java.util.EnumMap类:把枚举类型转换为映射类型。它的EnumMap(Class<K> keyType)构造方法用来指定具体的枚举类型。枚举常量以key的形式存放在map中。

下面是使用:

需求:定义一个表示不同颜色的枚举类,现在要求把枚举类对应的常量和颜色打印出来。

思路:使用EnumMap,将常量和颜色放入map中;然后将map再转化为set集合,集合中的元素变为键值对对象,然后通过获取key和value打印出结果。

package com.xupu.testinnerclass;

import java.util.EnumMap;
import java.util.Map;
import java.util.Set;

public class ColorTest {
    //表示颜色的枚举类
    enum Color{
        RED,
        GREEN,
        BLUE,
        YELLOW,
        PINK
    }

    public static void main(String[] args) {
        EnumMap<Color,String> colormap=new EnumMap<Color, String>(Color.class);
        colormap.put(Color.RED,"红色");
        colormap.put(Color.GREEN,"绿色");
        colormap.put(Color.BLUE,"蓝色");
        colormap.put(Color.YELLOW,"黄色");
        colormap.put(Color.PINK,"粉色");

        Set<Map.Entry<Color,String>> set=colormap.entrySet();
        for(Map.Entry entry:set){
            System.out.println(entry.getKey()+"="+entry.getValue());
        }
    }
}

单例设计模式、多例设计模式和枚举类型