一、单例模式
<span style="font-family:Microsoft YaHei;font-size:12px;">主要包括懒汉式,饿汉式,登记式,以及懒汉式的改进型,还有一个关于读取propertoes配置文件的实例。</span>
<span style="font-family:Microsoft YaHei;font-size:12px;">单例模式是设计模式中比较简单的一种。适合于一个类只有一个实例的情况,比如窗口管理器,打印缓冲池和文件系统, 它们都是原型的例子。典型的情况是,那些对象的类型被遍及一个软件系统的不同对象访问,因此需要一个全局的访问 指针,这便是众所周知的单例模式的应用。当然这只有在你确信你不再需要任何多于一个的实例的情况下。 单例模式的用意在于前一段中所关心的。通过单例模式你可以: 一、确保一个类只有一个实例被建立 二、提供了一个对对象的全局访问指针 三、在不影响单例类的客户端的情况下允许将来有多个实例 经典的单例模式有三种,懒汉式、饿汉式和 登记式。 懒汉式的特点是延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉么,很懒的,配置文件的实例直到用到的时候才会加载。</span></span>
饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式就是“空间换时间”,因为一开始就创建了实例,所以每次用到的之后直接返回就好了。
让我们先看下代码:
懒汉式:
- //懒汉式单例模式
- public class MySingleton {
- //设立静态变量
- private static MySingleton mySingleton = null;
- private MySingleton(){
- //私有化构造函数
- ("-->懒汉式单例模式开始调用构造函数");
- }
- //开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回
- public static MySingleton getInstance(){
- ("-->懒汉式单例模式开始调用公有方法返回实例");
- if(mySingleton == null){
- ("-->懒汉式构造函数的实例当前并没有被创建");
- mySingleton = new MySingleton();
- }else{
- ("-->懒汉式构造函数的实例已经被创建");
- }
- ("-->方法调用结束,返回单例");
- return mySingleton;
- }
- }
- public class Client {
- /**
- * 懒汉式单例模式
- * MySingleton
- */
- public static void myprint(){
- ("-----------------懒汉式单例模式----------------");
- ("第一次取得实例(懒汉式)");
- MySingleton s1 = ();
- ("第二次取得实例(懒汉式)");
- MySingleton s2 = ();
- if(s1==s2){
- (">>>>>s1,s2为同一实例(懒汉式)<<<<<");
- }
- ();
- }
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- //懒汉式
- myprint();
- //饿汉式
- //myprint2();
- //懒汉式改进
- //myprint2a();
- //登记式
- //myprint3();
- }
- }
输出结果为:
-----------------懒汉式单例模式----------------
第一次取得实例(懒汉式)
-->懒汉式单例模式开始调用公有方法返回实例
-->懒汉式构造函数的实例当前并没有被创建
-->懒汉式单例模式开始调用构造函数
-->方法调用结束,返回单例
第二次取得实例(懒汉式)
-->懒汉式单例模式开始调用公有方法返回实例
-->懒汉式构造函数的实例已经被创建
-->方法调用结束,返回单例
>>>>>s1,s2为同一实例(懒汉式)<<<<<
可以看出,在第一次调用公有方法的时候,并没有实例,所以我们创建了一个实例,之后再访问的时候,因为已经有一个已经创建好的实例,所以直接返回了。
饿汉式:
- //饿汉式单例模式
- public class MySingleton2 {
- //设立静态变量,直接创建实例
- private static MySingleton2 mySingleton = new MySingleton2();
- private MySingleton2(){
- //私有化构造函数
- ("-->饿汉式单例模式开始调用构造函数");
- }
- //开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回
- public static MySingleton2 getInstance(){
- ("-->饿汉式单例模式开始调用公有方法返回实例");
- return mySingleton;
- }
- }
看下客户端的测试代码:
- /**
- * 饿汉式单例模式
- * MySingleton2
- */
- public static void myprint2(){
- ("-----------------饿汉式单例模式----------------");
- ("第一次取得实例(饿汉式)");
- MySingleton2 s1 = ();
- ("第二次取得实例(饿汉式)");
- MySingleton2 s2 = ();
- if(s1==s2){
- (">>>>>s1,s2为同一实例(饿汉式)<<<<<");
- }
- ();
- }
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- //懒汉式
- //myprint();
- //饿汉式
- myprint2();
- //懒汉式改进
- //myprint2a();
- //登记式
- //myprint3();
- }
输出结果为:
-----------------饿汉式单例模式----------------
第一次取得实例(饿汉式)
-->饿汉式单例模式开始调用构造函数
-->饿汉式单例模式开始调用公有方法返回实例
第二次取得实例(饿汉式)
-->饿汉式单例模式开始调用公有方法返回实例
>>>>>s1,s2为同一实例(饿汉式)<<<<<
总结一下,两种方案的构造函数和公用方法都是静态的(static),实例和公用方法又都是私有的(private)。但是饿汉式每次调用的时候不用做创建,直接返回已经创建好的实例。这样虽然节省了时间,但是却占用了空间,实例本身为static的,会一直在内存中带着。懒汉式则是判断,在用的时候才加载,会影响程序的速度。最关键的是,在并发的情况下,懒汉式是不安全的。如果两个线程,我们称它们为线程1和线程2,在同一时间调用getInstance()方法,如果线程1先进入if块,然后线程2进行控制,那么就会有两个实例被创建。
二、代理模式
PROXY—跟MM在网上聊天,一开头总是“hi,你好”,“你从哪儿来呀?”“你多大了?”“身高多少呀?”这些话,真烦人,写个程序做为我的Proxy吧,凡是接收到这些话都设置好了自动的回答,接收到其他的话时再通知我回答,怎么样,酷吧。
代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
/**
* @author Rollen-Holt 设计模式之 代理模式
*/
interface NetWork{
public abstract void browser();
}
/**
* Real 类代表用户上网的实际动作,比如查看网页
* */
class Real implements NetWork{
public void browser(){
("上网浏览信息");
}
}
/**
* 此处使用代理类来完成中间代理的工作,屏蔽实现代理的细节
* */
class proxy implements NetWork{
private NetWork netWork;
proxy(NetWork netWork){
= netWork;
}
public void browser(){
checkName();
();
}
private void checkName(){
// Other codes
}
}
class hello{
public static void main(String[] a){
new proxy(new Real()).browser();
}
}
三、工厂模式
一、工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
1)简单工厂模式(Simple Factory):不利于产生系列产品;
2)工厂方法模式(Factory Method):又称为多形性工厂;
3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;
二、简单工厂模式
简单工厂模式又称 静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。
在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。
三、工厂方法模式
工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。
来看下它的组成:
代码:
public interface Moveable {
void run();
}
//具体产品角色
public class Plane implements Moveable {
@Override
public void run() {
("plane....");
}
}
public class Broom implements Moveable {
@Override
public void run() {
("broom.....");
}
}
//抽象工厂
public abstract class VehicleFactory {
abstract Moveable create();
}
public class PlaneFactory extends VehicleFactory{
public Moveable create() {
return new Plane();
}
}
public Moveable create() {
return new Broom();
}
}
public class Test {
public static void main(String[] args) {
VehicleFactory factory = new BroomFactory();
Moveable m = ();
();
}
}
可以看出工厂方法的加入,使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。因为如果不能避免这种情 况,可以考虑使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实 现。
四、简单工厂和工厂方法模式的比较
工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。
反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了。
五、抽象工厂模式
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
@Override
public Food createFood() {
return new Apple();
}
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Weapon createWeapon() {
return new AK47();
}
}
public static void main(String[] args) {
AbstractFactory f = new DefaultFactory();
Vehicle v = ();
();
Weapon w = ();
();
Food a = ();
();
}
}
六、总结。
(1) 简单工厂模式是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。
(2)工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。
(3)抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。