持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
简述:工厂模式是属于创建型模式,这种模式的初衷就是为了不在代码中显示new一个实例化对象,而是使用某种方法“生产”出来,工厂模式顾名思义就是用工厂生产对象。
一、 简单工厂模式,又称静态工厂(Static Factory Method)模式。
可以根据不同的参数返回不同的对象实例。就是从最我们最熟知最基础的每次手动new一个实例对象转变成工厂new;
简单工厂有三种角色,Factory(工厂角色)、Product(抽象产品角色)、ConcreteProduct(具体产品类),可以增加一个client客户类作调用。流程就是client通过factory获取一个ConcreteProduct。
简单工厂模式实际上没什么技术可言,并且违背了开闭原则,并不属于23种设计模式。(1995 年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了 23 种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF设计模式」。)
类图如下:
// 兵器--Product(抽象产品角色)
public interface Weapon {
// 战斗
String fight();
}
// 剑--ConcreteProduct(具体产品类)
public class Sword implements Weapon{
@Override
public String fight() {
return "我有一剑,可以搬山海!";
}
}
// 枪(矛)--ConcreteProduct(具体产品类)
public class Spear implements Weapon{
@Override
public String fight() {
return "我有一枪,可以破苍穹!";
}
}
// 铁匠铺--Factory(工厂角色)
public class Smithy {
public static Weapon getWeapon(String weaponName) throws Exception
{
if (weaponName.equalsIgnoreCase("spear")){
return new Spear();
} else if (weaponName.equalsIgnoreCase("sword")){
return new Sword();
} else {
throw new Exception("对不起,本店暂无此业务,但是你可以先给钱。");
}
}
}
// 儿女情长什么的,影响我行走江湖了
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 武林大赛擂台
class ChallengeArena{
public static void main(String[] args) throws Exception {
// 中文当变量名,没想到吧!!!
Person 陈平安 = new Person("陈平安");
Weapon sword = Smithy.getWeapon("sword");
System.out.println(陈平安.getName()+":"+sword.fight());
Person 赵子龙 = new Person("赵子龙");
Weapon spear = Smithy.getWeapon("spear");
System.out.println(赵子龙.getName()+":"+spear.fight());
}
}
那么现在问题来了,关二爷也想参赛怎么办,得有青龙偃月啊,步骤如下:
(1)添加具体产品类(刀--falchion)并实现抽象产品类(武器--Weapon)
(2)铁匠铺(工厂角色--Smithy)需要增加锻刀的业务(增加代码--所谓违背了开闭原则就在这里)
(3)关二爷(Person)报名参赛(ChallengeArena)
缺点:很明显了,违背了开闭原则,增加业务类型就需要增加代码,并修改原有代码; 优点:优点也是有的,编写代码比较简单,比较容易阅读--几个角色之间关系比较直观。
二、 工厂模式(Factory Pattern)
基于简单工厂模式的进步,修复了简单工厂模式违背开闭原则的缺陷,属于23种设计模式之一。
从设计的角度来看,工厂模式相对于简单工厂模式多了抽象工厂,原来简单模式是一个抽象产品对应多个具体产品,而现在工厂模式是增加了一个抽象工厂,一个抽象工厂对应多个具体工厂,每一种具体产品对应一个具体工厂。(文字还是太枯燥了)
直接上类图!
再来上代码!
// 超级铁匠铺--抽象工厂
public interface SuperSmithy {
Weapon getWeapon();
}
// 枪(矛)铁匠铺--(具体工厂)
public class SpearSmithy implements SuperSmithy{
@Override
public Weapon getWeapon() {
return new Spear();
}
}
// 剑铁匠铺--(具体工厂角色)
public class SwordSmithy implements SuperSmithy{
@Override
public Weapon getWeapon() {
return new Sword();
}
}
// 兵器--Product(抽象产品角色)
public interface Weapon {
// 战斗
String fight();
}
// 剑--ConcreteProduct(具体产品类)
public class Sword implements Weapon{
@Override
public String fight() {
return "我有一剑,可以搬山海!";
}
}
// 枪(矛)--ConcreteProduct(具体产品类)
public class Spear implements Weapon{
@Override
public String fight() {
return "我有一枪,可以破苍穹!";
}
}
// 儿女情长什么的,影响我行走江湖了
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 武林大赛擂台
class ChallengeArena{
public static void main(String[] args) throws Exception {
Person 陈平安 = new Person("陈平安");
Weapon sword = new SwordSmithy().getWeapon();
System.out.println(陈平安.getName()+":"+sword.fight());
Person 赵子龙 = new Person("赵子龙");
Weapon spear = new SpearSmithy().getWeapon();
System.out.println(赵子龙.getName()+":"+spear.fight());
}
}
可以看出来,剑(具体产品)有对应的剑之铁匠铺(具体工厂),枪(矛)(具体产品)也有对应的枪之铁匠铺(具体工厂),行走江湖的侠客们想要武器就去专门的铁匠铺就行。
那如果现在关二爷又想参赛怎么办,步骤如下:
(1)添加具体产品类(刀--falchion)并实现抽象产品类(武器--Weapon)
(2)直接添加锻刀的铁匠铺(具体工厂角色--FalchionSmithy)并实现抽象工厂(抽象工厂--SuperSmithy)
(3)关二爷(Person)报名参赛(ChallengeArena)
在第二步的时候不用修改原来的代码了,也就是不用违背开闭原则了
缺点:缺点就是每增加一项业务就增加一个具体产品+一个具体工厂,代码量upupup 优点:不用违背开闭原则了
三、 抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式是这几个模式最复杂的,工厂模式是每一种产品都有专门的工厂,比如专门铸剑的铁匠铺、专门锻刀的铁匠铺,简单来说产品跟工厂是一对一的关系。属于23种设计模式之一。
而抽象工厂把这种一对一关系打破了,使得一个工厂可以生产多样产品,比如铁匠铺可以锻件,也可以锻造铠甲,这里引入了产品族与产品等级的概念,同样原材料的是一样的产品族(比如这里陨铁是一个族,金精有又是一个族),生产同样属性的是同样的产品等级(比如这里攻击属性--刀枪剑戟是同一个产品等级,防御属性又是一个等级)。
当然了,产品族跟产品等级就是自定义的,比如下面是电器工厂的产品族与产品等级
从这里可以看出,抽象工厂又是普通工厂的进阶版本,普通工厂只会生产同样产品等级的产品(比如只生产攻击属性的刀枪剑戟),当然抽象工厂也会比普通工厂复杂许多,不论是原理还是代码方面。所以下面代码类的命名我直接用拼音了……不然我会乱
简要说明一下: (1)抽象工厂接口--超级铁匠铺,可以锻造武器、铠甲。
(2)具体工厂类--陨铁铁匠铺,可以锻造陨铁武器、铠甲;和金精铁匠铺,可以锻造金精武器、铠甲。
(3)抽象产品接口--武器,可以攻击;铠甲,可以防御。
(4)具体产品类--陨铁剑--攻击;陨铁铠甲--防御;金精剑--攻击;金精铠甲--防御;
代码如下:
// 超级铁匠铺--抽象工厂
public interface SuperSmithy {
// 锻造兵器
Weapon getWeapon();
// 锻造铠甲
Armor getArmor();
}
// 使用金精的铁匠铺--具体工厂
public class JinJingSmithy implements SuperSmithy{
@Override
public Weapon getWeapon() {
return new JinJingWeapon();
}
@Override
public Armor getArmor() {
return new JinJingArmor();
}
}
// 使用陨铁的铁匠铺--具体工厂
public class YunTieSmithy implements SuperSmithy{
@Override
public Weapon getWeapon() {
return new YunTieWeapon();
}
@Override
public Armor getArmor() {
return new YunTieArmor();
}
}
// 兵器--Product(抽象产品角色)
public interface Weapon {
// 战斗
String fight();
}
// 金精剑 -- 具体产品
public class JinJingWeapon implements Weapon{
@Override
public String fight() {
return "金精剑攻击";
}
}
// 陨铁剑 -- 具体产品
public class YunTieWeapon implements Weapon{
@Override
public String fight() {
return "陨铁剑攻击";
}
}
// 铠甲--Product(抽象产品角色)
public interface Armor {
// 防御
String defense();
}
// 金精铠甲 -- 具体产品
public class JinJingArmor implements Armor{
@Override
public String defense() {
return "金精铠甲防御";
}
}
// 陨铁铠甲 -- 具体产品
public class YunTieArmor implements Armor{
@Override
public String defense() {
return "陨铁铠甲防御";
}
}
package creativePattern.abstractFactoryPattern;
/**
* @author AKE
* @create 2022-05-31-15:56
*/
// 儿女情长什么的,影响我行走江湖了
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 武林大赛擂台
class ChallengeArena{
public static void main(String[] args) throws Exception {
Person 陈平安 = new Person("陈平安");
// 金精剑
Weapon 陈平安weapon = new JinJingSmithy().getWeapon();
// 陨铁铠甲
Armor 陈平安armor = new YunTieSmithy().getArmor();
System.out.println(陈平安.getName()+":"+陈平安weapon.fight()+":"+陈平安armor.defense());
Person 李太白 = new Person("李太白");
// 陨铁剑
Weapon 李太白weapon = new YunTieSmithy().getWeapon();
// 金精铠甲
Armor 李太白armor = new JinJingSmithy().getArmor();
System.out.println(李太白.getName()+":"+李太白weapon.fight()+":"+李太白armor.defense());
}
}
其实工厂模式跟抽象工厂模式已经很明显了,把抽象工厂模式理解为坐标轴的话,工厂模式只是其中一部分(产品等级,参照上面给出的图);
抽象工厂模式虽然功能最强大,但也是最难理解的;同时抽象工厂也会违背开闭原则的,如果新增加一个具体产品类,那么相对应的工厂类代码也需要扩展。