设计模式(单例、代理、工厂)

一、单例模式

<span style="font-family:Microsoft YaHei;font-size:12px;">主要包括懒汉式,饿汉式,登记式,以及懒汉式的改进型,还有一个关于读取propertoes配置文件的实例。</span>
<span style="font-family:Microsoft YaHei;font-size:12px;">单例模式是设计模式中比较简单的一种。适合于一个类只有一个实例的情况,比如窗口管理器,打印缓冲池和文件系统,
它们都是原型的例子。典型的情况是,那些对象的类型被遍及一个软件系统的不同对象访问,因此需要一个全局的访问
指针,这便是众所周知的单例模式的应用。当然这只有在你确信你不再需要任何多于一个的实例的情况下。 
单例模式的用意在于前一段中所关心的。通过单例模式你可以: 
一、确保一个类只有一个实例被建立 
二、提供了一个对对象的全局访问指针 
三、在不影响单例类的客户端的情况下允许将来有多个实例
经典的单例模式有三种,懒汉式、饿汉式和 登记式。
懒汉式的特点是延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉么,很懒的,配置文件的实例直到用到的时候才会加载。</span></span>

饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式就是“空间换时间”,因为一开始就创建了实例,所以每次用到的之后直接返回就好了。

让我们先看下代码:

懒汉式:

[java]  view plain copy print ?
  1. //懒汉式单例模式  
  2. public class MySingleton {  
  3.   
  4.     //设立静态变量  
  5.     private static MySingleton mySingleton = null;  
  6.   
  7.     private MySingleton(){  
  8.         //私有化构造函数  
  9.         System.out.println("-->懒汉式单例模式开始调用构造函数");  
  10.     }  
  11.       
  12.     //开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回  
  13.     public static MySingleton getInstance(){  
  14.         System.out.println("-->懒汉式单例模式开始调用公有方法返回实例");  
  15.         if(mySingleton == null){  
  16.             System.out.println("-->懒汉式构造函数的实例当前并没有被创建");  
  17.             mySingleton = new MySingleton();  
  18.         }else{  
  19.             System.out.println("-->懒汉式构造函数的实例已经被创建");  
  20.         }  
  21.         System.out.println("-->方法调用结束,返回单例");  
  22.         return mySingleton;  
  23.     }  
  24. }  
看下客户端的测试代码:

[java]  view plain copy print ?
  1. public class Client {  
  2.       
  3.     /** 
  4.      * 懒汉式单例模式 
  5.      * MySingleton 
  6.      */  
  7.     public static void myprint(){  
  8.         System.out.println("-----------------懒汉式单例模式----------------");  
  9.         System.out.println("第一次取得实例(懒汉式)");  
  10.         MySingleton s1 = MySingleton.getInstance();  
  11.         System.out.println("第二次取得实例(懒汉式)");  
  12.         MySingleton s2 = MySingleton.getInstance();  
  13.         if(s1==s2){  
  14.             System.out.println(">>>>>s1,s2为同一实例(懒汉式)<<<<<");  
  15.         }  
  16.         System.out.println();  
  17.     }  
  18.         /** 
  19.      * @param args 
  20.      */  
  21.     public static void main(String[] args) {  
  22.         // TODO Auto-generated method stub  
  23.         //懒汉式  
  24.         myprint();  
  25.         //饿汉式  
  26.         //myprint2();  
  27.         //懒汉式改进  
  28.         //myprint2a();  
  29.         //登记式  
  30.         //myprint3();  
  31.   
  32.     }  
  33.   
  34. }  

输出结果为:

-----------------懒汉式单例模式----------------
第一次取得实例(懒汉式)
-->懒汉式单例模式开始调用公有方法返回实例
-->懒汉式构造函数的实例当前并没有被创建
-->懒汉式单例模式开始调用构造函数
-->方法调用结束,返回单例
第二次取得实例(懒汉式)
-->懒汉式单例模式开始调用公有方法返回实例
-->懒汉式构造函数的实例已经被创建
-->方法调用结束,返回单例
>>>>>s1,s2为同一实例(懒汉式)<<<<<


可以看出,在第一次调用公有方法的时候,并没有实例,所以我们创建了一个实例,之后再访问的时候,因为已经有一个已经创建好的实例,所以直接返回了。

饿汉式

[java]  view plain copy print ?
  1. //饿汉式单例模式  
  2. public class MySingleton2 {  
  3.   
  4.     //设立静态变量,直接创建实例  
  5.     private static MySingleton2 mySingleton = new MySingleton2();  
  6.   
  7.     private MySingleton2(){  
  8.         //私有化构造函数  
  9.         System.out.println("-->饿汉式单例模式开始调用构造函数");  
  10.     }  
  11.       
  12.     //开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回  
  13.     public static MySingleton2 getInstance(){  
  14.         System.out.println("-->饿汉式单例模式开始调用公有方法返回实例");  
  15.         return mySingleton;  
  16.     }  
  17. }  

看下客户端的测试代码:

[java]  view plain copy print ?
  1. /** 
  2.  * 饿汉式单例模式 
  3.  * MySingleton2 
  4.  */  
  5. public static void myprint2(){  
  6.     System.out.println("-----------------饿汉式单例模式----------------");  
  7.     System.out.println("第一次取得实例(饿汉式)");  
  8.     MySingleton2 s1 = MySingleton2.getInstance();  
  9.     System.out.println("第二次取得实例(饿汉式)");  
  10.     MySingleton2 s2 = MySingleton2.getInstance();  
  11.     if(s1==s2){  
  12.         System.out.println(">>>>>s1,s2为同一实例(饿汉式)<<<<<");  
  13.     }  
  14.     System.out.println();  
  15. }  
[java]  view plain copy print ?
  1. /** 
  2.  * @param args 
  3.  */  
  4. public static void main(String[] args) {  
  5.     // TODO Auto-generated method stub  
  6.     //懒汉式  
  7.     //myprint();  
  8.     //饿汉式  
  9.     myprint2();  
  10.     //懒汉式改进  
  11.     //myprint2a();  
  12.     //登记式  
  13.     //myprint3();  
  14.   
  15. }  

输出结果为:

-----------------饿汉式单例模式----------------
第一次取得实例(饿汉式)
-->饿汉式单例模式开始调用构造函数
-->饿汉式单例模式开始调用公有方法返回实例
第二次取得实例(饿汉式)
-->饿汉式单例模式开始调用公有方法返回实例
>>>>>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(){
        System.out.println("上网浏览信息");
    }
}
/**
 * 此处使用代理类来完成中间代理的工作,屏蔽实现代理的细节
 * */
class proxy implements NetWork{
    private NetWork netWork;
 
    proxy(NetWork netWork){
        this.netWork = netWork;
    }
 
    public void browser(){
        checkName();
        this.netWork.browser();
    }
 
    private void checkName(){
        // Other codes
    }
}
class hello{
    public static void main(String[] a){
        new proxy(new Real()).browser();
    }
}


三、工厂模式

一、工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

 

工厂模式在《Java与模式》中分为三类:
1)简单工厂模式(Simple Factory):不利于产生系列产品;

2)工厂方法模式(Factory Method):又称为多形性工厂;

3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;
                         这三种模式从上到下逐步抽象,并且更具一般性。
                         GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。


二、简单工厂模式

简单工厂模式又称 静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。

在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。
              先来看看它的组成:

                 1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。

                 2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。

                 3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。

三、工厂方法模式

工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。
  来看下它的组成:

             1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

             2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

             3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

             4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
             工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代 码。可以看出工厂角色的结构也是符合开闭原则的!

代码:
//抽象产品角色
public interface Moveable {
    void run();
}
//具体产品角色
public class Plane implements Moveable {
    @Override
    public void run() {
        System.out.println("plane....");
    }
}

public class Broom implements Moveable {
    @Override
    public void run() {
        System.out.println("broom.....");
    }
}

//抽象工厂
public abstract class VehicleFactory {
    abstract Moveable create();
}
//具体工厂
public class PlaneFactory extends VehicleFactory{
    public Moveable create() {
        return new Plane();
    }
}
public class BroomFactory extends VehicleFactory{
    public Moveable create() {
        return new Broom();
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        VehicleFactory factory = new BroomFactory();
        Moveable m = factory.create();
        m.run();
    }
}


可以看出工厂方法的加入,使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。因为如果不能避免这种情 况,可以考虑使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实 现。

四、简单工厂和工厂方法模式的比较

工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。 
反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了。

五、抽象工厂模式
代码:
//抽象工厂类
public abstract class AbstractFactory {
    public abstract Vehicle createVehicle();
    public abstract Weapon createWeapon();
    public abstract Food createFood();
}
//具体工厂类,其中Food,Vehicle,Weapon是抽象类,
public class DefaultFactory extends AbstractFactory{
    @Override
    public Food createFood() {
        return new Apple();
    }
    @Override
    public Vehicle createVehicle() {
        return new Car();
    }
    @Override
    public Weapon createWeapon() {
        return new AK47();
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        AbstractFactory f = new DefaultFactory();
        Vehicle v = f.createVehicle();
        v.run();
        Weapon w = f.createWeapon();
        w.shoot();
        Food a = f.createFood();
        a.printName();
    }
}
在抽象工厂模式中,抽象产品 (AbstractProduct) 可能是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式。

六、总结。

(1) 简单工厂模式是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。 
(2)工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。 
(3)抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值