什么是工厂方法
定义一个创建产品对象的工厂接口,让子类决定实例化哪一个类,将实际创建工作推迟到子类当中。它的核心结构有四个角色,分别是
- 【抽象工厂】Factory : 具体工厂类必须实现这个接口。在实际的系统中,这个角色也常常使用抽象类实现。
- 【具体工厂】ConcreteFactory : 实现了抽象工厂接口的具体类。具体工厂角色含有与业务密切相关的逻辑。
- 【抽象产品】Product : 定义具体产品类所需要实现的逻辑和功能方法。
- 【具体产品】 ConcreteProduct : 实现具体逻辑和功能的类。
结构类图
举个栗子
漫威电影里每个英雄都有各自的能力/技能【+ skill()】,下面我们简单的用【智力】,【力量】,【格斗技巧】来分配对应的英雄,这样就可以对抗不同实力的敌人。
工厂及具体实现工厂【HeroFactrory】
public interface iHeroFactory {//定义具体工厂类所需要实现的逻辑和功能方法。
iHero callTheHero();
}
class StrengthFactory implements iHeroFactory {//力量型英雄选择工厂
@Override
public iHero callTheHero() {
return new Hulk();
}
}
public class FightFactory implements iHeroFactory {//格斗型英雄选择工厂
@Override
public iHero callTheHero() {
return new Hawkeye();
}
}
public class IqFactory implements iHeroFactory {//智力型英雄选择工厂
@Override
public iHero callTheHero() {
return new USACaptain();
}
}
产品及具体实现的产品【Hero】
interface iHero {//定义具体产品类所需要实现的逻辑和功能方法。
void skill();//定义旗下产品都有的技能方法
}
class Hulk implements iHero {
@Override
public void skill() {
System.out.println("【绿巨人】【智力:5】【力量:7】【格斗技巧:5】");
}
}
class Hawkeye implements iHero {
@Override
public void skill() {
System.out.println("【鹰眼】【智力:5】【力量:3】【格斗技巧:7】");
}
}
class USACaptain implements iHero {
@Override
public void skill() {
System.out.println("【美国队长】【智力:6】【力量:3】【格斗技巧:6】");
}
}
英雄分配和调度【客户程序】
iHeroFactory factory1=new FightFactory();//来一个会格斗的
iHero hero1=factory1.callTheHero();
hero1.skill();
System.out.println("\n------------------------------------\n");
iHeroFactory factory2=new StrengthFactory();//来一个力气大的
iHero hero2=factory2.callTheHero();
hero2.skill();
System.out.println("\n------------------------------------\n");
iHeroFactory factory3=new IqFactory();//来一个聪明的
iHero hero3=factory3.callTheHero();
hero3.skill();
需求改变
使用工厂方法后,调用端的耦合度大大降低了。例如上面这个栗子,比如说新出现了一个需求
美国队长叛变!广电总局说了,把美国队长封杀,全部换成钢铁侠来完成任务。
现实中应该也会遇到这种需求,例如把所有的图片加载(例如之前使用imageLoader),全部改成Glide。如果你之前通过工厂方法来封装的图片加载,那么改一句代码即可。
public class IqFactory implements iHeroFactory {//智力型英雄选择工厂
@Override
public iHero callTheHero() {
// return new USACaptain();
return new IronMan();//我们只需要在工厂里替换【英雄】(产品)即可
}
}
总结
工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口。那我们是否一定要在代码中遍布工厂呢?大可不必。也许在下面情况下你可以考虑使用工厂方法模式:
- 当客户程序不需要知道要使用对象的创建过程。
- 客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。