稳固而知新 SINGLETON,MONOSTATE,NULL OBJECT

来源:互联网 发布:linux运维工程师职责 编辑:程序博客网 时间:2024/05/17 07:13

SINGLETON
       一个类在应用程序中只有一个实例,在程序启动的时候被创建,在程序结束时被删除,通常此类作为基础对象,工厂对象或管理对象。
形式1
public class SingletonA {
       private static SingletonA instance = null;
 
       private SingletonA() {
       }
 
       public static SingletonA getInstance() {
              if (instance == null) {
                     instance = new SingletonA();
              }
              return instance;
       }
}
形式2
public class SingletonB {
 
       private static SingletonB instance = new SingletonB();
 
       private SingletonB() {
       }
 
       public static SingletonB getInstance() {
              return instance;
       }
}
Singleton的构造方法必须要私有化,防止其他类将其实例化。
 
好处:1适用于任何类,任何类都可以很容易的改造成此模式。
        2延迟装载,如果没有使用,不会创建实例。
 
代价:1无法摧毁,静态实例一直存在。
           2不能继承,不能通过派生使子类也实现Singleton模式。
           3不透明,使用者必须明确的知道正在使用一个Singleton。
           4 频繁的if校验,影响速度。
示例:


    应用程序读写LDAP server上的用户信息需要调用JNDI API,从而导致访问JNDI API的代码遍布程序各处,运用Singleton模式构建UserManager类,统一负责访问JNDI API,应用程序读写用户信息只需要调用UserManager.getInsance(),唯一实例保证了不会多个线程同时读写用户信息,而且很容易在UserManager中放入检查,计数,锁等机制。
 
 
MONOSTATE
通过把变量变为静态变量,使得类的多个对象可以共享相同的变量。
模型:
public class Monostate {
       private static int x = 0;
       public void setX(int y) {
              x = y;
       }
       public int getX() {
              return x;
       }
}
 
好处: 1 透明性: 使用者不需要知道对象是Monostate
              2 可派生: Monostate 的派生类也是Monostate,它们共享相同的静态变量
              3 多态性: 在派生类中可以override父类方法,因为方法不是静态(静态方法是不能override的)
代价: 1 不可转换 不能通过派生将常规类转为Monostate模式。
              2效率和内存占用,因为既是是对象,有具有静态变量成员,所以会有创建回收的开销和静态成员变量始终占据的内存空间的开销。
 
实例: 每一个User的实例在界面显示的时候需要提供User的图片,如果每个实例都保存一个Image对象,势必造成庞大的内存开销,在iPASS项目中,如果每个EMS对象都自己保存一个Image对象,1000个EMS时,程序就已经out of memory了(解决过此问题单,而且情况也比本例要复杂)。运用Monostate模式,如果每个User实例可以共享同一个Image实例,节省了内存的开销。
public class User {
       private static Image image = null;
       private String name;
       public Image getImage() {
              return image;
       }
       public void setImage(Image i) {
              image = i;
       }
}
 
 
NULL OBJECT
 
IEMS e = EmsManager.getEMS("emsname");
if (e != null && !e.isConnective()) {
              e.connect();
}
    此段代码在程序中随处可见,可以说遍布程序的各个角落,而且很多时候由于忘记对null进行检查而出现NullPointer异常。这种用法本身也是丑陋而且易出错。如果为null时,可以抛出异常,也可以减少出错的可能性,但出错处理的代码更加难以维护, 所以可以采用Null Object模式。
public interface IEMS {
       public boolean isConnective();
 
       public void connect();
 
       public static final IEMS NULL = new IEMS() {
              public boolean isConnective() {
                     return false;
              };
              public void connect() {
              };
       };
}
IEMS接口中有一个名为NULL的静态变量持有一个匿名IEMS实现体,这个实现体是无效EMS的唯一实例。这样就可以保证了无效EMS只有单一实例。可以通过if(e==IEMS.NULL)来判断e是否为无效EMS。使用该模式避免了对返回值进行NULL验证,即使无效也有返回对象,这个无效对象代表了什么也不做。以下是使用的方式:
IEMS ems = EmsManager.getEMS("emsname");
if (!ems.isConnective()) {
       ems.connect();
}
个人觉得也不是任何情况都可以使用此模式,有些时候还是需要返回null。