23种设计模式
工厂模式的分类
- 简单工厂(Simple Factory)模式
- 工厂方法(Factory Method)模式
- 抽象工厂(Abstract Factory)模式
为什么要用工厂模式
- 满足开闭原则:对修改关闭,对扩展开放。就是别改老代码,只需要添代码,以前所有的老代码,都是有价值的,需要尽力保留
- 解耦 :把对象的创建和使用的过程分开
- 降低代码重复: 如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。
- 降低维护成本 :由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建对象B的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
三个工厂模式区别
- 简单工厂:把对象的创建放到一个工厂类中,通过参数来创建不同的对象。
这个缺点是每添一个对象,就需要对简单工厂进行修改(尽管不是删代码,仅仅是添一个if,但仍然违背了“不改代码”的原则) - 工厂方法:每种产品由一种工厂来创建,一个工厂保存一个new基本完美,完全遵循 “不改代码”的原则
- 抽象工厂:可生成多个产品
不用工厂模式
就用打游戏中的枪械,AK47和M4A1来举例吧。
代码结构
代码
AK47.java
public class AK47 {
public void shot() {
System.out.println("AK47 shot");
}
}
M4A1.java
public class M4A1 {
public void shot() {
System.out.println("M4A1 shot");
}
}
Main.java
public class Main {
public static void main(String[] args) {
AK47 ak47 = new AK47();
M4A1 m4a1 = new M4A1();
ak47.shot();
m4a1.shot();
}
}
简单工厂模式
介绍
简单工厂模式是属于创建型模式,又叫做静态工厂方法模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。调用只需要告诉工厂类所需要的类型,工厂类就会返回需要的产品类工厂的子类。 可以说是工厂模式中最简单的一种。
简单工厂与OOP原则
已遵循的原则
- 依赖倒置原则
- 迪米特法则
- 里氏替换原则
- 接口隔离原则
未遵循的原则
- 开闭原则(如上文所述,利用配置文件+反射或者注解可以避免这一点)
- 单一职责原则(工厂类即要负责逻辑判断又要负责实例创建)
代码
简单工厂角色分配
- 工厂(Factory)角色:GunFactory
- 抽象产品(Product)角色:Gun
- 具体产品(Concrete Product)角色:AK47,M4A1
代码结构
Gun.java
public interface Gun {
void shot();
}
AK47.java
public class AK47 implements Gun{
public void shot() {
System.out.println("AK47 shot");
}
}
M4A1.java
public class M4A1 implements Gun{
public void shot() {
System.out.println("M4A1 shot");
}
}
GunFactory.java
public class GunFactory {
public Gun createGun(String gunName) {
if (gunName.equalsIgnoreCase("AK47")) {
return new AK47();
} else if (gunName.equalsIgnoreCase("M4A1")){
return new M4A1();
}
return null;
}
}
Main.java
public class Main {
public static void main(String[] args) {
Gun ak47 = new GunFactory().createGun("AK47");
Gun m4a1 = new GunFactory().createGun("M4A1");
ak47.shot();
m4a1.shot();
}
}
补充:反射机制改善简单工厂
GunFactory2.java
public class GunFactory2 {
public static Object createGun(Class<? extends Gun> clazz) {
Object obj = null;
try {
obj = Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
Main2.java
public class Main2 {
public static void main(String[] args) {
AK47 ak47 = (AK47) GunFactory2.createGun(AK47.class);
ak47.shot();
}
}
简单工厂存在问题
最重要的是它违背了我们在概述中说的 开放-封闭原则 (虽然可以通过反射的机制来避免,后面我们会介绍到) 。因为每次你要新添加一个功能,都需要在生switch-case 语句(或者if-else 语句)中去修改代码,添加分支条件。
简单工厂模式的优缺点
优点
- 屏蔽产品的具体实现,调用者只关心产品的接口。
- 实现简单
缺点
- 增加产品,需要修改工厂类,不符合开放-封闭原则
- 工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则
工厂方法模式
介绍
在工厂方法模式中,工厂父类定义创建产品对象的公共接口,具体的工厂子类负责创建具体的产品对象。每一个工厂子类负责创建一种具体产品。
工厂方法模式是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说 每个对象都有一个与之对应的工厂 。
工厂模式与OOP原则
已遵循的原则
- 依赖倒置原则
- 迪米特法则
- 里氏替换原则
- 接口隔离原则
- 单一职责原则(每个工厂只负责创建自己的具体产品,没有简单工厂中的逻辑判断)
- 开闭原则(增加新的产品,不像简单工厂那样需要修改已有的工厂,而只需增加相应的具体工厂类)
未遵循的原则
- 开闭原则(虽然工厂对修改关闭了,但更换产品时,客户代码还是需要修改)
代码
工厂方法模式角色分配
- 抽象工厂(Abstract Factory)角色:GunFactory
- 具体工厂(Concrete Factory)角色 :AK47Factory,M4A1Factory
- 抽象产品(AbstractProduct)角色:Gun
- 具体产品(Concrete Product)角色:AK47,M4A1
代码结构
文件太多了,为了方便演示,功能类似的集中写在一个地方。
Gun.java, AK47.java, M4A1.java
public interface Gun {
void shot();
}
public class AK47 implements Gun{
@Override
public void shot() {
System.out.println("AK47 shot");
}
}
public class M4A1 implements Gun{
@Override
public void shot() {
System.out.println("M4A1 shot");
}
}
GunFactory.java, AK47Factory.java, M4A1Factory.java
public interface GunFactory {
Gun createGun();
}
public class AK47Factory implements GunFactory {
@Override
public Gun createGun() {
return new AK47();
}
}
public class M4A1Factory implements GunFactory {
@Override
public Gun createGun() {
return new M4A1();
}
}
Main.java
public static void main(String[] args) {
GunFactory ak47Factory = new AK47Factory();
GunFactory m4a1Factory = new M4A1Factory();
Gun ak47 = ak47Factory.createGun();
Gun m4a1 = m4a1Factory.createGun();
ak47.shot();
m4a1.shot();
}
工厂方法模式的优缺点
优点
- 继承了简单工厂模式的优点
- 符合开放-封闭原则
缺点
- 增加产品,需要增加新的工厂类,导致系统类的个数成对增加,在一定程度上增加了系统的复杂性。
抽象工厂模式
介绍
抽象工厂模式(Factory Method Pattern)中,抽象工厂提供一系列创建多个抽象产品的接口,而具体的工厂负责实现具体的产品实例。抽象工厂模式与工厂方法模式最大的区别在于抽象工厂中每个工厂可以创建多个种类的产品。
抽象工厂模式与OOP原则
已遵循的原则
- 依赖倒置原则(工厂构建产品的方法均返回产品接口而非具体产品,从而使客户端依赖于产品抽象而非具体)
- 迪米特法则
- 里氏替换原则
- 接口隔离原则
- 单一职责原则(每个工厂只负责创建自己的具体产品族,没有简单工厂中的逻辑判断)
- 开闭原则(增加新的产品族,不像简单工厂那样需要修改已有的工厂,而只需增加相应的具体工厂类)
未遵循的原则
- 开闭原则(虽然对新增产品族符合开-闭原则,但对新增产品种类不符合开-闭原则)
代码
抽象工厂方法模式角色分配
- 抽象工厂(AbstractFactory)角色 :Factory
- 具体工厂类(ConreteFactory)角色 :AK47Factory,M4A1Factory
- 抽象产品(Abstract Product)角色 :Bullet,Gun
- 具体产品(Concrete Product)角色 :AK47Bullet,M4A1Bullet,AK47,M4A1
代码结构
Bullet.java, AK47Bullet.java, M4A1Bullet.java
public interface Bullet {
void load();
}
public class AK47Bullet implements Bullet {
@Override
public void load() {
System.out.println("AK47Bullet load");
}
}
public class M4A1Bullet implements Bullet {
@Override
public void load() {
System.out.println("M4A1Bullet load");
}
}
Gun.java,AK47.java,M4A1.java
public interface Gun {
void shot();
}
public class AK47 implements Gun{
@Override
public void shot() {
System.out.println("AK47 shot");
}
}
public class M4A1 implements Gun{
@Override
public void shot() {
System.out.println("M4A1 shot");
}
}
Factory.java, AK47Factory.java, M4A1Factory.java
public interface Factory {
Gun createGun();
Bullet createBullet();
}
public class AK47Factory implements Factory {
@Override
public Gun createGun() {
return new AK47();
}
@Override
public Bullet createBullet() {
return new AK47Bullet();
}
}
public class M4A1Factory implements Factory {
@Override
public Gun createGun() {
return new M4A1();
}
@Override
public Bullet createBullet() {
return new M4A1Bullet();
}
}
Main.java
public class Main {
public static void main(String[] args) {
Factory ak47Factory = new AK47Factory();
Bullet ak47Bullet = ak47Factory.createBullet();
Gun ak47 = ak47Factory.createGun();
ak47Bullet.load();
ak47.shot();
Factory m4a1Factory = new M4A1Factory();
Bullet m4a1Bullet = m4a1Factory.createBullet();
Gun m4a1 = m4a1Factory.createGun();
m4a1Bullet.load();
m4a1.shot();
}
}
抽象工厂的工厂和工厂方法中的工厂有什么区别呢?
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
参考
http://www.jasongj.com/design_pattern/simple_factory/
https://segmentfault.com/a/1190000015050674
https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/creational.html
https://www.zhihu.com/question/24843188