所谓的单例设计模式指的是一个类只允许产生一个实例化对象。

单例设计模式

范例: 一个简单程序

class Singleton {
    public void print() {
        System.out.println("Hello world !");
    }
}
public class TestSingleton {
    public static void main(String[] args) {
        Singleton s = null; //声明对象
        s = new Singleton(); //实例化对象
        s.print();
    }
}

以上程序在实例化的时候调用了Singleton类的无参构造方法,因为在在Singleton类里面并没有提供任何的构造方法,所以会自动一个无参的,什么都不做的构造方法。但是如果现在将Singleton类明确定义一个私有的构造方法。

class Singleton {
    private Singleton() {} //所有的方法都可以使用四种访问权限
    public void print() {
        System.out.println("Hello world !");
    }
}

这个时候类中明确的提供有一个私有的构造方法,那么默认无参的构造方法将不会自动生成,那么此时再进行对象实例化的时候一定会有错误。

TestSingleton.java:10: 错误: Singleton()可以在Singleton中访问private s = new Singleton(); //实例化对象

首先一旦构造方法被私有化了,那么就表示外部无法调用构造了,也就证明外部不能产生新的实例化对象。此时的类是一个相对而言封闭的状态了。

可是如果要想继续调用Singleton类中print()普通方法,那么就必须提供有实例化对象。于是根据封装的特点,可以考虑在类的内部产生一个实例化对象。

class Singleton {
    //在类的内部是可以访问私有的结构
    Singleton instance = new Singleton();//内部产生实例化对象
    private Singleton() {} //所有的方法都可以使用四种访问权限
    public void print() {
        System.out.println("Hello world !");
    }
}

现在Singleton类内部的instance对象(属性)是一个普通属性,所有的普通属性必须在有实例化对象的时候才有内存空间的分配,而现在外部无法产生实例化对象,所以在Singleton类在没有实例化对象产生的时候也可以将instance进行使用。这时候就需要static关键字。

class Singleton {
    //在类的内部是可以访问私有的结构
    static Singleton instance = new Singleton();//内部产生实例化对象
    private Singleton() {} //所有的方法都可以使用四种访问权限
    public void print() {
        System.out.println("Hello world !");
    }
}
public class TestSingleton {
    public static void main(String[] args) {
        Singleton s = null; //声明对象
        s = Singleton.instance; //实例化对象
        s.print();
    }
}

以上虽然可以取得了Singleton类的实例化对象,但是对于类中的属性应使用private封装,而如果要想取得封装的属性,就必须提供一个getter方法,而访问的是一个static属性,并且这个属性无法在外部进行实例化对象的创建,所以应该在提供一个static方法,因为static方法也不受实例化的控制。

class Singleton {
    //在类的内部是可以访问私有的结构
    private static Singleton instance = new Singleton();//内部产生实例化对象
    public static Singleton getInstance() {
        return instance;
    }
    private Singleton() {} //所有的方法都可以使用四种访问权限
    public void print() {
        System.out.println("Hello world !");
    }
}
public class TestSingleton {
    public static void main(String[] args) {
        Singleton s = null; //声明对象
        s = Singleton.getInstance(); //实例化对象
        s.print();
    }
}

这样的目的只希望类中产生唯一的实例化对象。

对于单例设计模式,也有两类形式:懒汉式、饿汉式;以上程序是饿汉式,不管是否使用Singleton类对象,只要该类加载了,那么一定会自动创建好一个公共的instance对象。

范例: 饿汉式单例

class Singleton {
    //在类的内部是可以访问私有的结构
    private static Singleton INSTANCE = new Singleton();//内部产生实例化对象
    public static Singleton getInstance() {
        return INSTANCE;
    }
    private Singleton() {} //所有的方法都可以使用四种访问权限
    public void print() {
        System.out.println("Hello world !");
    }
}

饿汉式:构造方法私有化,只能通过static方法获取实例化对象。 懒汉式:当第一次去使用Singleton类对象时才会为其实例化的处理操作。

范例: 懒汉式单例

class Singleton {
    //在类的内部是可以访问私有的结构
    private static Singleton instance;
    public static Singleton getInstance() {
        if(intance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    private Singleton() {} //所有的方法都可以使用四种访问权限
    public void print() {
        System.out.println("Hello world !");
    }
}

多例设计(理解)

多例的对象的类实际上生活中也经常出现,例如:要求描述一周天数的类,只能有7个对象,描述性别的类只能有两个。多例只是比单例追加了更多个内部实例化对象。

范例: 定义一个表示性别的多例类

class Gender {
    public static final int MALE_CMD = 1;
    public static final int FEMALE_CMD = 2;
    private static final Gender  MALE = new Gender("男");
    private static final Gender  FEMALE = new Gender("女");
    private String title;
    private Gender(String title) {
        this.title = title;
    }
    public static Gender getInstance(int ch) {
        switch(ch) {
            case MALE_CMD:
                return MALE;
            case FEMALE_CMD:
                return FEMALE;
            default:
                return null;
        }
    }
    public String toString() {
        return this.title;
    }
}
public class TestSingleton {
    public static void main(String[] args) {
        Gender s = null; //声明对象
        s = Gender.getInstance(Gender.MALE_CMD); //实例化对象
        System.out.println(s.toString());
    }
}

不管多例还是单例特点很明显:

  • 构造方法私有化;
  • 累内部一定会提供一个static方法用于取得实例化对象。