设计模式学习–工厂方法模式
工厂方法模式也是一个很常见、很基础的设计模式,属于创建型模式。它屏蔽了创建对象的细节,使用者可以直接使用,而不用去关心具体的实现逻辑。
定义
Define an interface for creating an object,but let subclasses decide which class to
instantiate.Factory Method lets a class defer instantiation to subclasses.
工厂模式(Factory Pattern)定义一个创建对象的接口,让其子类决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类,类图如下:
这里,我们用了召唤师创建英雄这一模型:
1.我们需要一个抽象英雄工厂类,其子类实现了创建英雄的逻辑(这里一般会引入泛型来限制入参和出参的类型)
/**
* 抽象英雄工厂类
* @Description:
* @author:wws
* @time:2018年8月21日 下午4:43:45
*/
public abstract class AbstractHeroFactory {
/**
* @Description:创建指定英雄的方法
* @param hero
* @return
* T
* @exception:
* @author: wws
* @time:2018年8月21日 下午4:47:51
*/
public abstract <T extends Hero> T createHero(Class<T> hero);
}
/**
* 英雄工厂类
* @Description:
* @author:wws
* @time:2018年8月21日 下午4:44:37
*/
public class HeroFactory extends AbstractHeroFactory{
@SuppressWarnings("unchecked")
@Override
public <T extends Hero> T createHero(Class<T> c) {
Hero hero = null;
try {
hero = (T)Class.forName(c.getName()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return (T)hero;
}
}
2.然后定义统一的英雄接口,包含了laugh(嘲讽)、play(游戏)两个基本方法,其子类则是具体的英雄,如赵信、烬、莫甘娜等
/**
* 英雄接口
* @Description:
* @author:wws
* @time:2018年8月21日 下午4:45:13
*/
public interface Hero {
/**
* @Description:嘲讽方法
* void
* @exception:
* @author: wws
* @time:2018年8月21日 下午5:10:28
*/
public void laugh();
/**
* @Description:游戏方法
*
* void
* @exception:
* @author: wws
* @time:2018年8月21日 下午5:10:44
*/
public void play();
}
/**
* 赵信
* @Description:
* @author:wws
* @time:2018年8月21日 下午5:09:54
*/
public class HeroZhaoXin implements Hero{
public void laugh() {
System.out.println("赵信:万军丛中取敌将首级");
}
public void play() {
System.out.println("赵信:蹲草丛、抓人");
}
}
/**
* 烬
* @Description:
* @author:wws
* @time:2018年8月21日 下午5:13:38
*/
public class HeroJin implements Hero{
public void laugh() {
System.out.println("烬:全场我望的最远");
}
public void play() {
System.out.println("望远烬:我要看看谁在打大龙");
}
}
3.最后召唤师使用main方法来调用createHero()方法
/**
* 召唤师
* @Description:
* @author:wws
* @time:2018年8月21日 下午5:08:13
*/
public class Summoner {
public static void main(String[] args) {
AbstractHeroFactory factory = new HeroFactory();
Hero zhaoXin = factory.createHero(HeroZhaoXin.class);
zhaoXin.laugh();
zhaoXin.play();
Hero jin = factory.createHero(HeroJin.class);
jin.laugh();
jin.play();
}
}
优点
- 封装性好、代码结构清晰
- 扩展性好,需要新的英雄(产品),只要新增一个类型就行
- 解耦,屏蔽产品细节,调用者无需关注具体的实现细节
缺点
每增加一个产品,就需要增加其工厂及实现类,当产品很多时,系统复杂度会很大
扩展
工厂模式是频繁产生对象最好的方式,同时也有很多扩展方式:
1. 简单工厂模式
简单工厂模式就是在工厂模式的基础上,拿掉了抽象工厂类,将原来工厂类的覆写方法改为静态方法,场景一般是应用中只有一个工厂模型,没有其他多余产品类,也被叫做静态工厂模式
2. 多个工厂模式
当一个产品类非常复杂时,如,每个英雄有自己的背景故事、技能、定位等,那我们就需要将抽象类的功能分解,不再定义参数,相应的功能则放到每个英雄工厂类中去,即:每个具体的工厂类明确自己的职责,负责创建自己的产品对象。
3. 替代单例模式
工厂模式也可以在内存中只创建唯一的对象,来替代单例模式
4. 延时初始化
一个对象被消费完,不立即释放,而是保存状态等待再次使用。一般工厂类中会对判断对象是否存在,存在直接返回,不存在则新建并返回使用,然后存入map中缓存。优点是,在创建对象比较复杂时,延时加载可以降低对象产生和销毁带来的复杂性,如JDBC的连接等。