讨论一:
既然只有一个类?为什么非要用一个模式来定义?难道就不能用程序员之间的约定又或者使用伟大的设计模式来完成?
1)先来说说全局变量的好处,当定义一个全局变量时,任何一个函数或者一行代码都可以轻松访问所有的全局变量,并且不用付出额外的代价,轻松简便。就如在敲机房收费的时候,我就定义机房登陆用户名为一个全局变量,因为在整个系统的执行过程中,很多方面都用到了用户名的信息,在此,调用全局变量,轻而易举就解决,很是方便。但是如果换成一个大型软件,又或者你的整个系统中定义了很多全局变量,这个时候使用起来就会比较混乱,使原本简单的事情变得复杂化了。
2)对于变量名的设定我觉得也是一个难题,如果过多的话真的会导致变量名的冲突,到时候无疑又给自己增加了一个难题。
3)当然最重要的一点,定义全局变量,无疑增加了模块与函数之间的耦合度,也就是说你已经把他们牢牢的拴在了一起,想要再重新修改,可就变得不是那么简单了。
来看看类图:
getInstance()方法是静态的,这意味着它是一个类方法,所以可以在代码的任何地方使用,其实这和全局变量使用起来是一样的,不过单件可以延迟实例化。
讨论二:
单例模式的使用之处:
有一些对象我们只使用一个,如threadpool,Cache,对话框,注册表对象,日志对象,充当打印机、显卡等设备的驱动程序的对象。
讨论三:简单而又不简单
简单之意:因为它只涉及到了一个类,所以最终“祸害”了大家,其实他是很调皮的!不过调皮归调皮,却还是蛮厉害的。
其实自己对于Chocolate还是蛮钟情的,如果自己能够开一个制造巧克力的工厂多好,这样既能用到自己所学的知识,还能满足自己的小胃口。不过这种甜食依旧还是少吃为好吧!
假如我们这有一个锅炉正在工作,而不知情的工作者又打开了一个锅炉,本来一个锅炉的原料就已经足够,再加一个,可想而知,会有多少浪费……
这时候我们就可以使用"Singleton"来帮你解决问题:
避免不知情的情况下再次打开一个锅炉,也就是把锅炉设计单件:
//巧克力制作一个单一的过程
public class ChocolateBoiler {
private boolean empty; //定义私有变量
private boolean boiled;
//uniqueInstance持有唯一的单件实例
private static ChocolateBoiler uniqueInstance;
private ChocolateBoiler(){
//开始时,锅炉是空的
empty=true;
boiled=true;
}
public static ChocolateBoiler getInstance()
{
if (uniqueInstance==null){
//System.out.println("Creating unique Instance of Chocolate Boiler");
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
public void fill() <span style="font-family: 华文新魏; font-size: 16pt; text-indent: 21pt;">{</span>
if (isEmpty()) {
empty = false;
boiled = false;
//填充混合物
}
}
但是执行完之后会发现,自己允许在加热的过程中继续加入原料,这可是会溢出的啊!我们唯一想到的原因就是刚刚使用的多线程对ChocolateBoiler进行了优化,来建立一个ChocolateCotroller来控制一下吧!
public class ChocolateController
{
public static void main(String args [])
{
ChocolateBoiler boiler = ChocolateBoiler.getInstance();
boiler.fill(); //填充
boiler.boil();<span style="white-space:pre"> </span> //煮沸方法
boiler.drain(); //排除煮沸的填充物的方法
// will return the existing instance
ChocolateBoiler boiler2= ChocolateBoiler.getInstance();
}
如果boiler在工作,那么boiler2只会听后指挥。
对于多线程的处理采用synchronized方法,也就是把getInstance()方法变成同步(synchronized)方法,多线程灾难轻而易举的就解决了!
//多线程处理
public static synchronized ChocolateBoiler getInstance()
{
if (uniqueInstance==null){
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
如果想在不改变执行效率的情况下,急切的创建实例,可以在一个静态初始化器创建单件,
Public class Singleton ChocolateBoiler
{
//在static initializer中创建单件,保证了线程安全
Private static ChocolateBoiler uniqueInstance = new ChocolateBoiler();
Private ChocolateBoiler() {}
Public static ChocolateBoiler getInstance()
{
Return uniqueInstance; //直接使用
}
}
当然最优化的方法,则是双重加锁,首先看代码:
private boolean empty;
private boolean boiled;
//当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值
private volatile static ChocolateFactory uniqueInstace=null;
private ChocolateFactory(){
empty=true;
boiled=true;
}
public static ChocolateFactory getInstance(){
if (uniqueInstace==null){
synchronized (ChocolateFactory.class){
if (uniqueInstace==null){
uniqueInstace=new ChocolateFactory();
}
}
}
return uniqueInstace;
}
唠叨了半天,其实就是三种对于巧克力锅炉代码多遇到的问题:
1)同步getInstance方法,保证可行的最直接的方法
2)急切实例化
3)双重检查枷锁()
三种方法是一个层层优化的过程,不过优化也要针对问题,对症下药才可!