【设计模式-工厂模式】从女娲造人看工厂模式
神话中,女娲创造出了人类,而人类的人种大致可分为3类:黄、白、黑
那么女娲是如何创造出这些不同的人种的人类?
假设女娲有一个炉子,女娲只需要将捏成人形的泥土放入其中,就可以根据不同的火候得到不同肤色的人种,这大致就就是女娲造人的过程。
在上面这段描述中,女娲其实就是一个场景类,负责业务逻辑的处理
炉子则是一个工厂类,根据 女娲的需要可以创造出不同肤色的人种
不同肤色的人种则是具体的产品类,他们都继承自同一个 抽象产品类 人类,而每个人有自己的肤色 以及有说话的能力
类图如下所示,为了更完整的说明工厂模式,现将女娲使用的炉子也抽象出来(女娲有不同的炉子,可以创造不同的生物)
女娲造人类图

代码
类图已经画出,那么试着用代码描述
首先我们需要先将产品(不同的产品)抽象出一个抽象产品(抽象类或者接口)。在本例中 从各色人种中抽象出来的是一个人类接口
public interface Human {
//每个人种的皮肤都是不同的颜色
public void getColor();
//每个人类都会发声
public void talk();
}
女娲创造出不同的人种都应该实现该接口
人种
黑色人种:
/**
* 黑色人种
* @author LiPeng01
* @since 2020/8/2 5:43 下午
*/
public class BlackHuman implements Human {
@Override
public void getColor() {
System.out.println("黑皮肤");
}
@Override
public void talk() {
System.out.println("非洲语");
}
}
黄色人种
package com.example.springboot.factory;
/**
* 黄色人种
* @author LiPeng01
* @since 2020/8/2 5:43 下午
*/
public class YellowHuman implements Human {
@Override
public void getColor() {
System.out.println("黄皮肤");
}
@Override
public void talk() {
System.out.println("国语");
}
}
白色人种:
package com.example.springboot.factory;
/**
* 白色人种
* @author LiPeng01
* @since 2020/8/2 5:43 下午
*/
public class WhiteHuman implements Human
{
@Override
public void getColor() {
System.out.println("白皮肤");
}
@Override
public void talk() {
System.out.println("英语");
}
}
炉子
确认完我们需要创建的人种后,我们需要个炉子能够烧制泥人为我们所需要的人种。
该炉子对使用者女娲来说,应该是一个黑盒。只需要女娲告诉炉子 她需要什么人种,炉子就可以自动创建出来该人种的一个人类,不需要女娲去知道炉子内部是怎么烧制的。
我们定义一个抽象类,该类的抽象方法是用于生产人类的,这里使用了泛型来接受不同人种
/**
* 抽象工厂(八卦炉)
* @author LiPeng01
* @since 2020/8/2 5:58 下午
*/
public abstract class AbstractHumanFactory {
/**
* 生产人类的方法
* @param c
* @param <T>
* @return
*/
public abstract <T extends Human> T createHuman(Class<T> c);
}
炉子有各种各样的,女娲目前需要的是一个能够烧制人类的炉子,所以我们需要创建个实现了抽象类的 阴阳八卦炉用于创建人类实例
package com.example.springboot.factory;
/**
* @author LiPeng01
* @since 2020/8/2 6:01 下午
*/
public class HumanFactory extends AbstractHumanFactory {
@Override
//T就是 Class<T>中的T, 先有Class<T>的定义,才能在这个Class中使用T作为泛型定义
public <T extends Human> T createHuman(Class<T> c) {
//定义一个生产的人种
Human human = null;
try{
//产生一个人种
human = (T)Class.forName(c.getName()).newInstance();
// human = c.newInstance();
} catch (Exception e) {
System.out.println("人种生成错误!");
}
return (T)human;
}
}
女娲
到目前为止,造人的工具以及需要造的人的类型我们都已经获得了,现在可以让女娲正式开始创建人类。女娲不需要知道炉子内部是怎么实现的,她只需要告诉炉子她所想要的人种,炉子就会自动为她创建一个实例。
package com.example.springboot.factory;
/**
* @author LiPeng01
* @since 2020/8/2 10:35 下午
*/
public class NvWa {
public static void main(String[] args) {
//声明一个八卦炉
AbstractHumanFactory yinYangLu = new HumanFactory();
//女娲第一次造人.火候不足,产生了白人
System.out.println("--制造白人--");
Human whiteHuman = yinYangLu.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
//第二次造人 火候过了,产生了黑人
System.out.println("--制造黑人--");
Human blackHuman = yinYangLu.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
//第三次造人,火候刚好,产生了黄人
System.out.println("--黄种人--");
Human yellowHuman = yinYangLu.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();
}
}
运行结果:
--制造白人--
白皮肤
英语
--制造黑人--
黑皮肤
非洲语
--黄种人--
黄皮肤
国语
工厂方法的定义
Define an interface for creating an object,but let subclasses decide whichclass to instantiate.Factory Method lets a class defer instantiation tosubclasses.(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)
通用类图

在工厂方法模式中,抽象产品类Porduct 负责定义产品的共性,实现对事物最抽象的定义; Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类则有具体的ConcreteCreator负责完成。
以女娲为例: 人类就是一个抽象产品类,它定义了人类的共性:说话和肤色;炉子则是一个抽象工厂,他的具体实现阴阳八卦炉则是专门用于创建人类的,而具体的创建规则则是在阴阳八卦炉里定义的。本例中就是根据场景传来的名称来决定。
好处
使用工厂类的好处是什么呢?
首先,工厂类实现了对代码的良好的封装,使得一个对象的创建得到约束。如果调用者需要得到一个具体的产品对象,他只需要告诉工厂类 目标对象的产品类名称即可得到该类实例,而对象的创建过程对调用者来说是透明的,也就降低了模块之间的耦合。
其次,拓展性得到了提升,如果需求变更需要新增加个肤色人种(如:棕色肤色) ,那么只需要在新增加个产品类即可。甚至哪天说想要把原来场景类中使用的人种换个肤色,也只需要改动下场景类的类名即可得到新人种的对象。这种在增加产品类的情况下,只需要适当的修改具体的工厂类或者扩展一个工厂类,就可以拥抱变化。
再次,使用工厂模式,使得场景类屏蔽了产品类。产品类的实现如何变化,调用者都不需要关注,只需要抽象产品类的接口不变化,那么调用者就不用变化。因为具体的实现是由工厂类负责。黑色人种也可以说国语,但是对调用者来说,这些变化都是对它没有任何影响的。
最后,工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类,没问题!

浙公网安备 33010602011771号