工厂模式
- 简单工厂
- 工厂方法
- 抽象工厂
简单工厂
我们以战士、射手、法师为示例。
当我们想创建这三个职业的对象时,可以新建一个英雄接口,所有继承了这个接口的对象都要实现攻击函数:
package com.cc.factory.simpleFactory;
/**
* 英雄接口
* @author cc
* @date 2021-12-16 17:34
*/
public interface Hero {
// 英雄可以进行攻击
void attack();
}
然后分别创建战士Warrior、射手Shooter以及法师Master:
package com.cc.factory.simpleFactory;
/**
* 战士
* @author cc
* @date 2021-12-16 17:39
*/
public class Warrior implements Hero {
@Override
public void attack() {
System.out.println("战士攻击");
}
}
package com.cc.factory.simplefactory;
/**
* 射手
* @author cc
* @date 2021-12-16 17:41
*/
public class Shooter implements Hero {
@Override
public void attack() {
System.out.println("射手攻击");
}
}
package com.cc.factory.simplefactory;
/**
* 法师
* @author cc
* @date 2021-12-16 17:41
*/
public class Master implements Hero {
@Override
public void attack() {
System.out.println("法师攻击");
}
}
接下来是生产英雄的简单工厂HeroSimpleFactory,这个工厂根据传入参数的不同来实例化不同对象:
package com.cc.factory.simpleFactory;
import com.cc.factory.simplefactory.Hero;
import com.cc.factory.simplefactory.Master;
import com.cc.factory.simplefactory.Shooter;
import com.cc.factory.simplefactory.Warrior;
/**
* 英雄简单工厂
* @author cc
* @date 2021-12-16 17:42
*/
public class HeroSimpleFactory {
public static Hero getHero(String type) {
Hero hero = null;
if ("warrior".equalsIgnoreCase(type)) {
hero = new Warrior();
} else if ("shooter".equalsIgnoreCase(type)) {
hero = new Shooter();
} else if ("master".equalsIgnoreCase(type)) {
hero = new Master();
}
return hero;
}
}
在main函数中调用这个英雄的简单工厂测试一下:
package com.cc.factory.simplefactory;
public class Main {
public static void main(String[] args) {
{
Hero hero = HeroSimpleFactory.getHero("warrior");
hero.attack();
}
{
Hero hero = HeroSimpleFactory.getHero("shooter");
hero.attack();
}
{
Hero hero = HeroSimpleFactory.getHero("master");
hero.attack();
}
}
}
结果:
战士攻击
射手攻击
法师攻击
简单工厂总结
通过这个示例,我们可以看出来,简单工厂的实现十分简单,所以如果系统本身不复杂的话可以采用简单工厂方案。
但是缺点也是明显的,比如如果我们设计出了新的英雄比如精灵、矮人,就要修改简单工厂的源代码,这违背了开闭原则(软件应该对拓展开放,对修改关闭,其含义是说软件应该通过扩展来实现变化,而不是通过修改已有代码来实现变化)。
所以为了遵循开闭原则,我们有了工厂方法模式。
工厂方法
还是上面关于英雄的示例,我们新建一个接口HeroFactory:
package com.cc.factory.factorymethod;
/**
* 英雄工厂
* @author cc
* @date 2021-12-16 17:55
*/
public interface HeroFactory {
// 获取英雄
void getHero();
}
然后新建三个英雄的工厂,工厂需要实现HeroFactory接口:
package com.cc.factory.factorymethod;
public class WarriorFacrtory implements HeroFactory {
@Override
public Hero getHero() {
return new Warrior();
}
}
package com.cc.factory.factorymethod;
public class ShooterFacrtory implements HeroFactory {
@Override
public Hero getHero() {
return new Shooter();
}
}
package com.cc.factory.factorymethod;
public class MasterFacrtory implements HeroFactory {
@Override
public Hero getHero() {
return new Master();
}
}
测试一下:
package com.cc.factory.factorymethod;
public class Main {
public static void main(String[] args) {
{
HeroFactory factory = new WarriorFacrtory();
Hero hero = factory.getHero();
hero.attack();
}
{
HeroFactory factory = new ShooterFacrtory();
Hero hero = factory.getHero();
hero.attack();
}
{
HeroFactory factory = new MasterFacrtory();
Hero hero = factory.getHero();
hero.attack();
}
}
}
结果:
战士攻击
射手攻击
法师攻击
这就是工厂方法的使用,和简单工厂不同的地方是,当我们增加了新的英雄之后,要创建对应的生产工厂,让子类工厂去实现英雄的创建,以拓展的形式实现功能,这符合开闭原则。
优点:工厂模式有十分好的拓展性,每个工厂只负责一个任务,这也符合了单一职责原则(即一个类只负责做一件事)
工厂方法总结
工厂方法有一个局限性,就是只创建一个对象,假设我们现在需要创建一组对象,比如英雄除了有attack()攻击行为,还会有武器装备,战士的武器装备是长剑、重甲;射手的武器装备的弓箭、皮甲;法师的武器装备是魔杖、布甲,
那么在工厂方法中,仅一个战士英雄,我们就需要创建英雄、长剑、重甲三个工厂类,这样的架构设计并不好,所以我们又有了抽象工厂。
抽象工厂
抽象工厂AbstractFactory声明了一组用于创建对象的方法,让我们来创建一个英雄的抽象工厂:
package com.cc.factory.abstractfactory;
/**
* 英雄抽象工厂
* @author cc
* @date 21-12-16 23:07
*/
public abstract class HeroAbstractFactory {
abstract Hero createHero();
abstract Weapon createWeapon();
abstract Equip createEquip();
}
这个英雄抽象工厂声明了三个方法,分别是创建英雄、创建武器和创建装备,所有继承了这个英雄抽象工厂的工厂类都要实现这三个方法,这样就实现了生产一组对象的目的。
先创建武器和装备的接口类:
package com.cc.factory.abstractfactory;
/**
* 武器
* @author cc
* @date 21-12-16 23:07
*/
public interface Weapon {
// 创建武器
void action();
}
package com.cc.factory.abstractfactory;
/**
* 装备
* @author cc
* @date 21-12-16 23:09
*/
public interface Equip {
// 创建装备
void action();
}
然后分别创建长剑、弓箭、魔杖和重甲、皮甲、布甲的类:
package com.cc.factory.abstractfactory;
/**
* 长剑类
* @author cc
* @date 21-12-16 23:11
*/
public class Sword implements Weapon {
@Override
public void action() {
System.out.println("创建长剑");
}
}
package com.cc.factory.abstractfactory;
/**
* 弓箭类
* @author cc
* @date 21-12-16 23:12
*/
public class Bow implements Weapon {
@Override
public void action() {
System.out.println("创建弓箭");
}
}
package com.cc.factory.abstractfactory;
/**
* 魔杖类
* @author cc
* @date 21-12-16 23:19
*/
public class Wand implements Weapon {
@Override
public void action() {
System.out.println("创建魔杖");
}
}
package com.cc.factory.abstractfactory;
/**
* 重甲类
* @author cc
* @date 21-12-16 23:15
*/
public class HeavyArmor implements Equip {
@Override
public void action() {
System.out.println("创建重甲");
}
}
package com.cc.factory.abstractfactory;
/**
* 轻甲类
* @author cc
* @date 21-12-16 23:15
*/
public class LeatherArmor implements Equip {
@Override
public void action() {
System.out.println("创建轻甲");
}
}
package com.cc.factory.abstractfactory;
/**
* 布甲类
* @author cc
* @date 21-12-16 23:16
*/
public class ClothArmor implements Equip {
@Override
public void action() {
System.out.println("创建布甲");
}
}
现在可以创建英雄的生产工厂了:
package com.cc.factory.abstractfactory;
/**
* 战士生产工厂
* @author cc
* @date 21-12-16 23:10
*/
public class WarriorFactory extends HeroAbstractFactory {
@Override
Hero createHero() {
return new Warrior();
}
@Override
Weapon createWeapon() {
return new Sword();
}
@Override
Equip createEquip() {
return new HeavyArmor();
}
}
package com.cc.factory.abstractfactory;
/**
* 射手生产工厂
* @author cc
* @date 21-12-16 23:29
*/
public class ShooterFactory extends HeroAbstractFactory {
@Override
Hero createHero() {
return new Shooter();
}
@Override
Weapon createWeapon() {
return new Bow();
}
@Override
Equip createEquip() {
return new LeatherArmor();
}
}
package com.cc.factory.abstractfactory;
/**
* 法师生产工厂
* @author cc
* @date 21-12-16 23:30
*/
public class MasterFactory extends HeroAbstractFactory {
@Override
Hero createHero() {
return new Master();
}
@Override
Weapon createWeapon() {
return new Wand();
}
@Override
Equip createEquip() {
return new ClothArmor();
}
}
测试一下:
package com.cc.factory.abstractfactory;
public class Main {
public static void main(String[] args) {
{
HeroAbstractFactory factory = new WarriorFactory();
Hero hero = factory.createHero();
Weapon weapon = factory.createWeapon();
Equip equip = factory.createEquip();
hero.attack();
weapon.action();
equip.action();
}
{
HeroAbstractFactory factory = new ShooterFactory();
Hero hero = factory.createHero();
Weapon weapon = factory.createWeapon();
Equip equip = factory.createEquip();
hero.attack();
weapon.action();
equip.action();
}
{
HeroAbstractFactory factory = new MasterFactory();
Hero hero = factory.createHero();
Weapon weapon = factory.createWeapon();
Equip equip = factory.createEquip();
hero.attack();
weapon.action();
equip.action();
}
}
}
结果:
战士攻击
创建长剑
创建重甲
射手攻击
创建弓箭
创建轻甲
法师攻击
创建魔杖
创建布甲
测试代码中我们可以看到,通过抽象工厂的实现,可以针对不同的工厂子类创建不同的英雄,并且对英雄的一组对象如武器装备进行实例化。
优点:抽象工厂可以在类的内部对组对象进行关联和定义,而不需要引入新的管理对象。
缺点:组对象的拓展会十分麻烦,如上示例,假如我们需要给英雄再添加一个释放技能的行为,需要修改所有的工厂方法,这又违背了开闭原则。
其实,当抽象工厂中只有一个组件的话,本质上和工厂方法是差不多的,具体要使用什么设计模式,还是要根据场景随机应变。