工厂方法模式(Factory Method Pattern)。

定义:

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

通用代码:

抽象产品类(Product)负责定义产品的共性

public abstract clas Product {

// 产品类的公共方法

public void method1(){

// 业务逻辑处理

}

// 抽象方法

public abstract void method2();

}

具体产品类(可以有多个,都继承于抽象产品类)

pubilc class ConcreteProduct1 extends Product {

public void method2(){

// 业务逻辑处理

}

}


pubilc class ConcreteProduct2 extends Product {

public void method2(){

// 业务逻辑处理

}

}

抽象工厂类(Creator为抽象创建类,也就是抽象工厂,负责定义产品)

public abstract class Creator {

/*

 * 创建一个产品对象,其输入参数类型可以自行设置

 * 通常为String、Enum、class等,当然也可以为空

 */

public abstract <T extends Product> T createProduct(Class<T> c);

}

具体工厂类(具体如何产生一个产品的对象,是由具体的工厂类创建的)

 

public class ConcreteCreator extends Creator {

public <T extends Product> T createProduct(Class<T> c) {

Product product = null;

try{

product = (Product) Class.forName(c.getName()).nextInstance();

} catch (Exception e) {

// 异常处理

}

return (T) product;

}

}

场景类

public class Client {

public static void main(String[] args) {

Creator creator = new ConcreteCreator();

Product product = creator.createProduct(ConcreteProduct1.class);

// 继续业务处理

}

}

优点:

  • 良好的封装性,代码结构清晰。
  • 工厂方法模式的扩展性非常优秀。
  • 屏蔽产品类。
  • 工厂方法模式时典型的解耦框架。

使用场景:

  • 工厂方法模式是new一个对象的替代品,所以在需要生成对象的地方都可以使用,但是需要慎重的考虑是否增加一个工厂类进行管理,增加代码的复杂度。
  • 需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式。
  • 工厂方法模式可以用在异构项目中。
  • 可以使用在测试驱动开发的框架下。例如,测试一个类A,就需要把与类A有关联关系的类B也同时产生出来,我们可以使用工厂方法模式把类B虚拟出来,避免类A与类B的耦合。目前由于JMock和EasyMock的诞生,该使用场景已经弱化了,读者可以在遇到此种情况时直接考虑使用JMock或EazyMock。

工厂方法模式的扩展

1、缩小为简单工厂模式

简单工厂模式(Simple Factory Pattern),也叫作静态工厂模式。在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式。

2、升级为多个工厂类

在复杂的应用中一般采用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂了类,对高层模块提供统一的方法接口。

3、替代单例模式

负责生成单例的工厂类

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;

}

}

4、延迟初始化(Lazy initialization)

定义:一个对象被消费完毕后,并不立即释放,工厂类保持其初始状态,等待再次被使用。

延迟加载的工厂类

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("Product1".equals(type)) {

product = new ConcreteProduct1();

} else {

product = new ConcreteProduct2();

}

// 同时把对象放到缓存容器中

prMap.put(type.product);

}

return product;

}

}

延迟加载框架时可以扩展的,例如限制某一个产品类的最大实例化数量,可以通过判断Map中已有的对象数量来实现,这样的处理是非常有意义的,例如JDBC连接数据库,都会要求社会一个MaxConnections最大连接数量,该数量就是内存中最大实例化的数量。

延迟加载还可以用在对象初始化比较复杂的情况下,例如硬件访问,涉及多方面的交互,则可以通过延迟加载降低对象的产生和销毁带来的复杂性。

最佳实践:

工厂方法模式在项目中使用得非常频繁,以至于很多代码中都包含工厂方法模式。该模式近乎人尽皆知,但不是每个人都能用得好。熟能生巧,熟练掌握该模式,多思考工厂方法如何应用,而且工厂方法模式还可以与其他模式混合使用(例如模板方法模式、单例模式、原型模式灯),变化出无穷的优秀设计,这也正是软件设计和开发的乐趣所在。

案例(女娲造人):

人类总称

public interface Human {

// 每个人种的皮肤都有相应的颜色

public void getColor();

// 人类会说话

public void talk();

}

黑色人种(黄色人种和白色人种省略)

public class BlackHuman implements Human {

public void getColor() {

System.out.println("黑色人种的皮肤颜色是黑色的!");

}

public void talk(){

System.out.println("黑人会说话,一般人听不懂。");

}

}

抽象人类创建工厂

public abstract class AbstractHumanFactory {

public abstract <T extends Human> T createHuman(Class<T> c);

}

注意,我们在这里采用了泛型(Generic),通过定义泛型对createHuman的输入参数产生两层限制:

  • 必须是Class类型;
  • 必须是Human的实现类。

其中的“T”表示的是,只要实现了Human接口的类都可以作为参数,泛型是JDK1.5中的一个非常重要的新特性,它减少了对象间的转换,约束其输入参数类型,对Collection集合下的实现类都可以定义泛型。

人类创建工厂

public class HumanFactory extends AbstractHumanFactory {

public <T extends Human> T createHuman(Class<T> c) {

// 定义一个生产的人种

Human human = null;

try {

// 产生一个人种

human = (T) Class.forName(c.getName()).newInstrance();

} catch (Exception e) {

System.out.println("人种生成错误!");

}

return (T) human;

}

}

女娲类
 

public class NvWa {

public static void main(String[] args) {

// 声明阴阳八卦炉

AbstractHumanFactory YinYangLu = new HumanFactory();

// 产生黑人

Human blackHuman = YinYangLu.createHuman(BlackHuman .class);

blackHuman.getColor();

blackHuman.talk(); 

}

}

简单工厂模式中的工厂类

public class HumanFactory {

public  static <T extends Human> T createHuman(Class<T> c) {

// 定义一个生产的人种

Human human = null;

try {

// 产生一个人种

human = (T) Class.forName(c.getName()).newInstrance();

} catch (Exception e) {

System.out.println("人种生成错误!");

}

return (T) human;

}

}

女娲类
 

public class NvWa {

public static void main(String[] args) {

// 声明阴阳八卦炉

AbstractHumanFactory YinYangLu = new HumanFactory();

// 产生黑人

Human blackHuman = HumanFactory.createHuman(BlackHuman .class);

blackHuman.getColor();

blackHuman.talk(); 

}

}

多工厂模式的抽象工厂类

public abstract class AbstractHumanFactory {

public abstract  Human createHuman();

}

黑色人种的创建工厂实现(白色人种和黄色人种省略)

public class BlackHumanFactory extends AbstractHumanFactory {
public Human createHuman() {

return new BlackHuman();

}
}

女娲类

public class NvWa {

public static void main(String[] args) {

// 声明阴阳八卦炉

AbstractHumanFactory YinYangLu = new HumanFactory();

// 产生黑人

Human blackHuman = (new BlackHumanFactory()).createHuman(BlackHuman .class);

blackHuman.getColor();

blackHuman.talk(); 

}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值