设计模式——0_0 工厂方法(Factory Method)

挫其锐,解其纷,和其光,同其尘

—— 《道德经》

定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到了子类


图纸

工厂模式图纸




一个例子:去找一支笔

几乎在所有的面向对象的编程语言里,我们可以通过如下方式新建一个对象:

A a = new A();

行话管这种写法叫 new一个对象 出来


比如,我的程序中有一个用于表示的类簇,就像这样:
笔的类簇


Pen 拥有写(write)画(draw)两种能力,用返回值说明绘制的结果是否成功。现在规定FountainPen(钢笔)要用来写字,而Pencil(铅笔)要用来画画。

我觉得你也不希望每次 new Pen的对象的时候得翻一下规定,于是我们为 Pen 制定了一个工厂类,就像这样:

笔和工厂

public interface BrushPot{
    
    //创建一支笔
    Pen createPen();
}

public class WritingPenBrushPot implements BrushPot{
    
    //新建一支用于写字的笔
    public Pen createPen(){
        return new FountainPen();//新建一支钢笔
    }
}

public class BrushBrushPot implements BrushPot{
    
    //新建一支用于画画的笔
    public Pen createPen(){
        return new Pencil();//新建一支铅笔
    }
}

这样一来,我的程序中就再也不会用new的方式去新建一个Pen的子类了,而是通过BrushPot来获取一个Pen的对象。这就实现了对笔创建时的 统一管理。此时,这个 BrushPot 事实上就担任了 Pen 的工厂类。到这里,工厂方法模式的例子其实就已经完成了


但是现在这个例子并没有展示工厂方法存在的意义,调用工厂方法来获取对象和直接new他并没有什么区别,这就意味着每次拿笔还要去买一支新的

作为一个钱镶在肾上的IT民工,这种浪费是可耻的

所以我要先去现有的笔里找一找,就像这样:

//笔筒的单例工厂实现
public interface BrushPot{
    
    //创建一支笔
    Pen createPen();
}

public class WritingPenBrushPot implements BrushPot{
    
    private static volatile Pen fountainPen;
    
    //新建一支用于写字的笔
    public Pen createPen(){
        if(fountainPen == null){
        	synchronized(WritingPenBrushPot.class){
        		if(fountainPen == null){//进锁之后再判断一次是否为空,保证线程安全
		        	fountainPen = new FountainPen();        			
        		}
        	}
        }
       	
        return fountainPen;//返还钢笔
    }
}

public class BrushBrushPot implements BrushPot{
    
    private static volatile Pen pencil;
    
    //新建一支用于画画的笔
    public Pen createPen(){
        if(pencil == null){ 
        	synchronized(BrushBrushPot.class){
        		if(pencil == null){
		            pencil = new Pencil();        			
        		}
        	}
        }
        
        return pencil;//返还铅笔
    }
}

现在,我们实现了整个程序都公用一支写字的钢笔,一支画画用的铅笔。物尽其用,功德圆满。虽然门口收废品的老大爷咬牙切齿,但是问题不大



笔和耐久度

但是我们知道笔这种东西总是不能无限制的使用的

钢笔有墨水,铅笔有笔芯

墨水用完了要加水,铅笔削完了要再买个新的

所以我们的Pen变成了这样:
笔和耐久度

我们在Pen中加入了durability(耐久度)的概念,并规定当isExhausted(是否是耗尽)返还true的时候,对 writedraw 的调用都是无效的

而在钢笔中,新增了addInk(添加墨水)方法,这个方法可以增加当前钢笔对象的耐久度值

于是乎,我们在笔筒中获取笔的时候,则会变成这样:

//笔筒的享元工厂实现
public interface BrushPot{
    
    //创建一支笔
    Pen createPen();
}

public class WritingPenBrushPot implements BrushPot{
    
    private static volatile Pen fountainPen;
    
    //新建一支用于写字的笔
    public Pen createPen(){        
        if(fountainPen == null){
            synchronized(WritingPenBrushPot.class){
        		if(fountainPen == null){//进锁之后再判断一次是否为空,保证线程安全
		        	fountainPen = new FountainPen();        			
        		}
        	}
        }else if(fountainPen.isExhausted()){
            synchronized(WritingPenBrushPot.class){
        		if(fountainPen.isExhausted()){//进锁之后再判断一次,保证线程安全
		            fountainPen.addInk();//给钢笔添加墨水
        		}
        	}
        }
       	
        return fountainPen;//返还钢笔
    }
}

public class BrushBrushPot implements BrushPot{
    
    private static volatile Pen pencil;
    
    //新建一支用于画画的笔
    public Pen createPen(){
        if(pencil == null || pencil.isExhausted()){
            synchronized(BrushBrushPot.class){
        		if(pencil == null || pencil.isExhausted()){
		            pencil = new Pencil();        			
        		}
        	}
        }
        
        return pencil;//返还铅笔
    }
}

对于调用代码来说,他依然是只使用 createWritingPencreateBrush 方法去获取写字笔和画笔,不需要因为笔上增加了耐久度做任何响应

这就是对对象的创建进行统一管理的意义,我们可以随意改变产出对象的策略,而调用代码对此一无所知




写在后面的碎碎念

平行类层次

当一个类将他的一些职责委托给另一个独立的类的时候,就产生了平行类层次

——《设计模式》

打个比方——手机和充电器

想必各位道友的手机都不会跟着一个固定的充电器,而是有一个接口用于充电。

而充电又是手机一个必要的功能。

很显然,你的手机将这个功能 委托 给了充电器

于是乎,手机和充电器之间,就形成了一个平行类层次,就像这样:

手机和充电器


这跟工厂模式有什么关系?

工厂模式去找一支笔 的UML中,我们都可以看到 产品根类工厂根类 之间存在一种逻辑上的关联

具体的某个产品和工厂之间,他们存在 1-1 的实际关系(一个工厂只生产一种产品)

那么最后你俯视 产品类簇工厂类簇 之间的关系的时候,就会得出一个类似 手机和充电器 那样的图纸

也就是说这个时候,产品类和工厂类之间,形成了平行类层次


作为平行类层次,产品类委托出去了什么能力呢?

答:产品类将创建自身的能力委托给了工厂方法



静态的工厂方法实现

由于具体的产品和工厂之间是一对一的,那么工厂方法也常常以一种在产品类上的静态方法来实现他;你还可以用这个工厂方法来替代构造方法

比如说现在有一个类叫 A,就像这样:

public class A{}

现在我想要一个专门用于生产 A 的工厂方法,这时是不需要特地在新增一个 AFactory 这样的类来专门生产 A的。而是通过在 A 类型上新增一个 static 类型的方法,来实现工厂方法,就像这样:

public class A{

     public static A createA(){
         return new A();
     }

     //私有化构造方法,这样一来就没有人可以从外部通过new A的方式创建A了
     private A(){}
}

为什么要用静态工厂方法代替构造方法

  • 静态工厂方法可以自定义方法名,构造方法的名字必须和类名一致

    自定义的方法名可以告知调用者很多信息,让看代码的人知道自己在产出什么状态的对象

    比如 Java 中的线程池

    ExecutorService e1 = Executors.newCachedThreadPool();//缓存型线程池
    ExecutorService e2 = Executors.newFixedThreadPool(5);//定长线程池
    ExecutorService e3 = Executors.newScheduledThreadPool(5);//周期性线程池
    ExecutorService e4 = Executors.newSingleThreadExecutor();//单线程线程池
    ……
    
  • 静态工厂方法可以返还多类型的结果,而构造方法只能返还当前类的对象

    比如说

    • 在用户传入异常的参数值的时候,静态工厂方法可以通过 返还null/其它值 的方式通知调用者,构造方法只能抛出异常
    • 静态工厂方法可以根据需要返还当前类的子类对象,而构造方法只能返还当前类的对象



参数化工厂

通过传入不同的参数要求工厂方法返还不同的具体产品

比如说在上文的 笔筒工厂 里面如果还要管理 颜色 属性的话,那么在 createWritingPencreateBrush 中恐怕就要添加 颜色 作为参数,再根据不同的颜色生成对应的笔了



工厂方法和简单工厂模式

先说结论,在23种基础设计模式里是没有简单工厂模式这个模式的,简单工厂顶多算是一种编程风格

工厂方法已经涵盖了简单工厂在里面,没有必要把简单工厂单独拿出来讲



为什么我们需要工厂模式,是new不好用吗?

有这样几个问题:

  • 一个对象应该在什么地方被创建?
  • 一个对象应该由谁来创建?
  • 一个对象应该如何创建?
  • 一个对象应该何时被创建?

怎么回答这样的问题,就是诸如 工厂方法、单例、原型 这样的创造型设计模式存在的意义

他们负责实例化并管理对象,同时把当前系统所使用的具体信息封装起来。在看不到源码的人眼里,他只是在使用顶层的产品接口

就像我知道我的笔记本电脑里一定有内存条,但是如果我不查,我永远不会知道他用了什么颗粒




万分感谢您看完这篇文章,如果您喜欢这篇文章,欢迎点赞、收藏。还可以通过专栏,查看更多与【设计模式】有关的内容

  • 38
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乡亲们啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值