设计模式笔记--工厂方法模式

常用设计模式有23中,分为:

创建型模式(主要用于创建对象)

 

1、单例模式    2、工厂方法模式    3、抽象工厂模式    4、建造者模式     5、原型模式 
行为型模式 (主要用于描述对象或类是怎样交互和怎样分配职责)

 

1、模板方法模式  2、中介者模式  3、命令模式    4、责任链模式   5、策略模式   6、迭代器模式  

7、观察者模式      8、备忘录模式   9、访问者模式   10、状态模式  11、解释器模式

结构型模式(主要用于处理类或对象的组合)

1、代理模式  2、装饰模式   3、适配器模式   4、组合模式   5、外观模式(门面模式)   6、享元模式   7、桥梁模式

 

工厂方法模式

 
其定义为: 
 
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类 。
 
  
在工厂方法模式中,抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义;
Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。  
 
 
抽象产品类代码如代码清单8-8所示。
<span style="font-size:18px;">public abstract class Product {
//产品类的公共方法
public void method1(){
//业务逻辑处理
}
//抽象方法
public abstract void method2();
}</span>
 
 
具体的产品类可以有多个,都继承于抽象产品类,其源代码如代码清单8-9所示。
<span style="font-size:18px;">public class ConcreteProduct1 extends Product {
public void method2() {
//业务逻辑处理
}
}p
ublic class ConcreteProduct2 extends Product {
public void method2() {
//业务逻辑处理
}
}</span>
 
 
抽象工厂类负责定义产品对象的产生,源代码如代码清单8-10所示。 
<span style="font-size:18px;">public abstract class Creator {
/*
* 创建一个产品对象,其输入参数类型可以自行设置
* 通常为String、Enum、Class等,当然也可以为空
*/
public abstract T createProduct(Class c);
}</span>
 
具体如何产生一个产品的对象,是由具体的工厂类实现的,如代码清单8-11所示。  
<span style="font-size:18px;">public class ConcreteCreator extends Creator {
public T createProduct(Class c){
Product product=null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T)product;
}
}</span>
 
 
场景类的调用方法如代码清单8-12所示。
<span style="font-size:18px;">public class Client {
public static void main(String[] args) {
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
/*
* 继续业务处理
*/
}</span>
 
该通用代码是一个比较实用、易扩展的框架,读者可以根据实际项目需要进行扩展。  
 
 
工厂方法模式的优点  
 
首先,良好的封装性,代码结构清晰。
 
其次,工厂方法模式的扩展性非常优秀  
 
再次,屏蔽产品类  
 
最后,工厂方法模式是典型的解耦框架  
 
 
使用场景
 
首先,工厂方法模式是new一个对象的替代品, 但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。 

其次,需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。  

再次,工厂方法模式可以用在异构项目中,  

最后,可以使用在测试驱动开发的框架下  
 
 
 
 
 
工厂方法模式的扩展  

 
1. 缩小为简单工厂模式  
 
如果 一个模块仅需要一个工厂类,没有必要把它产生出来,使用静态的方法就可以了,  
 
 
2. 升级为多个工厂类 
 
在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化会使代码结构不清晰。
 
例如,一个产品类有5个具体实现,每个实现类的初始化(不仅仅是new,初始化包括new一个对象,并对对象设置一定的初始值)方法都不相同,如果写在一个工厂方法中,势必会导致该方法巨大无比,那该怎么办?
 
考虑到需要结构清晰,我们就为每个产品定义一个创造者,然后由调用者自己去选择与哪个工厂方法关联。我们还是以女娲造人为例,每个人种都有一个固定的八卦炉,分别造出黑色人种、白色人种、黄色人种,修改后的类图如图8-4所示。  
 
 
 
注意 抽象方法中已经不再需要传递相关参数了,因为每一个具体的工厂都已经非常明 确自己的职责:创建自己负责的产品类对象。  
 
每一个产品类都对应了一个创建类,好处就是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带来了一定的影响。  
 
当然,在复杂的应用中一般采用多工厂的方法,然后会再增加一个 协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。  
 
3.  替代单例模式
 
 
定义了一个private的无参构造函数 ,
<span style="font-size:18px;">代码清单8-20 单例类
public class Singleton {
//不允许通过new产生一个对象
private Singleton(){
}
public void doSomething(){
//业务处理
}
}</span>

 
通过反射方式创建,通过获得类构造器,然后设置访问权限,生成一个对象,然后提供外部访问,保证内存中的对象唯一  
<span style="font-size:18px;">代码清单8-21 负责生成单例的工厂类
public class SingletonFactory {
private static Singleton singleton;
static{
try {
Class cl= Class.forName(Singleton.class.getName());
//获得无参构造
Constructor constructor=cl.getDeclaredConstructor();
//设置无参构造是可访问的
constructor.setAccessible(true);
//产生一个实例对象
singleton = (Singleton)constructor.newInstance();
} catch (Exception e) {
//异常处理
}
}
public static Singleton getSingleton(){
return singleton;
}
}</span>

 
4. 延迟初始化
 
延迟初始化(Lazy initialization)?一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。
 
 
 
ProductFactory负责产品类对象的创建工作,通过定义一个Map容器,容纳所有产生的对象,如果在Map容器中已经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容器中,以方便下次调用。    
<span style="font-size:18px;">public class ProductFactory {
private static final Map<String,Product> prMap = new HashMap();
public static synchronized Product createProduct(String type) throws Exception{
Product product =null;
//如果Map中已经有这个对象
if(prMap.containsKey(type)){
product = prMap.get(type);
}else{
if(type.equals("Product1")){
product = new ConcreteProduct1();
}else{
product = new ConcreteProduct2();
}
//同时把对象放到缓存容器中
prMap.put(type,product);
}
return product;
}
}</span>
 
延迟加载框架是可以扩展的,例如限制某一个产品类的最大实例化数量,可以通过判断Map中已有的对象数量来实现,这样的处理是非常有意义的  
 
延迟加载还可以用在对象初始化比较复杂的情况下,例如硬件访问,涉及多方面的交互,则可以通过延迟加载降低对象的产生和销毁带来的复杂性。  
 
 

 

5.应用场景

  • 生成复杂对象时,无需知道具体类名,只需知道相应的工厂方法即可。

6.优点

  • 符合开放封闭原则。新增产品时,只需增加相应的具体产品类和相应的工厂子类即可。
  • 符合单一职责原则。每个具体工厂类只负责创建对应的产品。

7.缺点

  • 一个具体工厂只能创建一种具体产品。
  • 增加新产品时,还需增加相应的工厂类,系统类的个数将成对增加,增加了系统的复杂度和性能开销。
  • 引入的抽象类也会导致类结构的复杂化。

8.Android中的源码分析

Android中的ThreadFactory就是使用了工厂方法模式来生成线程的,线程就是ThreadFactory的产品。

8.1 ThreadFactory相关源码分析

 

    //抽象产品:Runnable
    public interface Runnable {
        public abstract void run();
    }
    
    //具体产品:Thread
    public class Thread implements Runnable {
        //构造方法
        public Thread(Runnable target, String name) {
            init(null, target, name, 0);
        }
        
        @Override
        //实现抽象产品的抽象方法
        public void run() {
            if (target != null) {
                target.run();
            }
        }
        
        //其他代码略
    }
    
    
    //抽象工厂:ThreadFactory
    public interface ThreadFactory {
        Thread newThread(Runnable r);
    }
    
    //具体工厂:AsyncTask中的实现
    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);
        
        //实现抽象工厂的抽象方法
        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());//返回Thread这个产品
        }
    };


 

 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值