《疯狂学习之Java设计模式之简单工厂模式》
《疯狂学习之Java设计模式之简单工厂模式》
目录
一、模式类型
二、模式定义
三、模式原理
1、模式组成
2、模式UML图
四、模式实际的应用
1、例子背景
2、代码验证
3、UML图
五、模式总结
1、优点
2、缺点
3、解决了哪些问题
4、应用场景
六、代码
一、模式类型
<b>简单工厂模式</b>属于<b>创建型模式</b>,但是它不属于23种设计模式中的任何一种,是工厂模式的简单化模式,又叫<b>静态工厂方法模式</b>。
二、模式定义
<b>简单工厂模式</b>:字面意思可以看出,这里会用到一个简单的工厂,现实中,我们都知道工厂是批量生成同一类不同属性的商品的地方,那么在代码中,我们拿工厂来批量创建同一类不同的对象,此时这个创建对象的类就是<b>"工厂类"</b>,<b>简单工厂模式</b>就是工厂类以一个简单的静态方法的形式,通过传递参数的不同来决定具体创建哪个具体产品对象。
三、模式原理
1、模式组成
抽象产品对象
这个类主要是将有规律的一类对象进行归类为一类,方便创建,代码如下:
/**
* 抽象产品
*
* @author pengzhan.qian
* @since 1.0.0
*/
public interface IProduct {
/**
* 打印产品名称
*/
void printProductName();
}具体产品对象
/**
* 具体产品A
*
* @author pengzhan.qian
* @since 1.0.0
*/
public class ProductA implements IProduct {
@Override
public void printProductName() {
System.out.println("I'm ProductA");
}
}
/**
* 具体产品B
*
* @author pengzhan.qian
* @since 1.0.0
*/
public class ProductB implements IProduct {
@Override
public void printProductName() {
System.out.println("I'm ProductB");
}
}
/**
* 具体产品C
*
* @author pengzhan.qian
* @since 1.0.0
*/
public class ProductC implements IProduct {
@Override
public void printProductName() {
System.out.println("I'm ProductC");
}
}产品对象工厂类
/**
* 抽象产品的工厂
* 可以根据传递的参数判断来创建具体的产品
*
* @author pengzhan.qian
* @since 1.0.0
*/
public class ProductFactory {
public static IProduct createProduct(String params) {
if ("A".equalsIgnoreCase(params)) {
return new ProductA();
} else if ("B".equalsIgnoreCase(params)) {
return new ProductB();
} else if ("C".equalsIgnoreCase(params)) {
return new ProductC();
} else {
return null;
}
}
}客户端
/**
* 客户端
*
* @author pengzhan.qian
* @since 1.0.0
*/
public class Client {
public static void main(String[] args) {
//客户需要A产品
IProduct productA = ProductFactory.createProduct("A");
assert productA != null;
try {
productA.printProductName();
} catch (Exception e) {
System.out.println("您需要的产品尚未开始生产");
}
//客户需要B产品
IProduct productB = ProductFactory.createProduct("B");
assert productB != null;
try {
productB.printProductName();
} catch (Exception e) {
System.out.println("您需要的产品尚未开始生产");
}
//客户需要C产品
IProduct productC = ProductFactory.createProduct("C");
assert productC != null;
try {
productC.printProductName();
} catch (Exception e) {
System.out.println("您需要的产品尚未开始生产");
}
//客户需要D产品
IProduct productD = ProductFactory.createProduct("D");
assert productD != null;
try {
productD.printProductName();
} catch (Exception e) {
System.out.println("您需要的产品尚未开始生产");
}
}
}客户端执行结果
I'm ProductA
I'm ProductB
I'm ProductC
您需要的产品尚未开始生产
2、模式UML图
四、模式实际应用
1、例子背景
我们经常遇到的场景:登录
我们现在社交百花齐放,登录的时候除了基础的用户名密码登录之外,还有手机号码验证码登录,邮箱密码登录等等。
而这个背景就很符合我们的简单工厂模式,将登录事件抽象为一个产品对象,不同的登录方式的登录就是一个个的具体的登录产品,此时我们为了统一的去一个方法解决多种方式的登录问题。
2、代码验证
将登录事件抽象为一个产品对象
/**
* 抽象的登录场景
*
* @author pengzhan.qian
* @since 1.0.0
*/
public interface ILogin {
/**
* 具体的登录逻辑
*/
void login();
}
不同的登录方式的登录就是一个个的具体的登录产品
/**
* @author pengzhan.qian
* @since 1.0.0
*/
public class UserNameAndPasswordLogin implements ILogin {
@Override
public void login() {
System.out.println("现在客户正在使用用户名和密码登录");
}
}
/**
* @author pengzhan.qian
* @since 1.0.0
*/
public class PhoneAndCaptchaLogin implements ILogin {
@Override
public void login() {
System.out.println("现在客户正在使用手机号码验证码登录");
}
}
/**
* @author pengzhan.qian
* @since 1.0.0
*/
public class EmailAndPasswordLogin implements ILogin {
@Override
public void login() {
System.out.println("现在客户正在使用邮箱账号和密码登录");
}
}工厂类就是统一方法
/**
* 登录工厂类
*
* @author pengzhan.qian
* @since 1.0.0
*/
public class LoginFactory {
/**
* 提前定义好前端传参 loginStyle
* loginStyle = 1 用户名密码登录
* loginStyle = 2 邮箱密码登录
* loginStyle = 3 手机号码验证码登录
*
* @param loginStyle
* @return
*/
public static ILogin selectLoginStyle(Integer loginStyle) {
ILogin login = null;
switch (loginStyle) {
case 1:
login = new UserNameAndPasswordLogin();
break;
case 2:
login = new EmailAndPasswordLogin();
break;
case 3:
login = new PhoneAndCaptchaLogin();
break;
default:
System.out.println("登录方式非法");
}
return login;
}
}客户端就是登录界面
/**
* 客户端 类似与登录界面的请求
*
* @author pengzhan.qian
* @since 1.0.0
*/
public class Client {
/**
* 这里的main方法类似于接口的controller
*
* @param args
*/
public static void main(String[] args) {
//A客户使用用户名密码进行登录 前端传参数 loginStyle = 1
ILogin loginA = LoginFactory.selectLoginStyle(1);
try {
loginA.login();
} catch (Exception e) {
System.out.println("错误的登录方式");
}
//B客户使用邮箱密码进行登录 前端传参数 loginStyle = 2
ILogin loginB = LoginFactory.selectLoginStyle(2);
try {
loginB.login();
} catch (Exception e) {
System.out.println("错误的登录方式");
}
//C客户使用手机号码验证码进行登录 前端传参数 loginStyle = 3
ILogin loginC = LoginFactory.selectLoginStyle(3);
try {
loginC.login();
} catch (Exception e) {
System.out.println("错误的登录方式");
}
//D客户使用第三方进行登录 前端传参数 loginStyle = 4
ILogin loginD = LoginFactory.selectLoginStyle(4);
try {
loginD.login();
} catch (Exception e) {
System.out.println("错误的登录方式");
}
}
}
执行结果:
现在客户正在使用用户名和密码登录
现在客户正在使用邮箱账号和密码登录
现在客户正在使用手机号码验证码登录
登录方式非法
错误的登录方式
3、UML图
五、模式总结
1、优点
解耦:将对象的具体的创建过程对使用者进行了屏蔽,使用者只需要通过工厂类选择参数来创建不同的实例对象即可
可读性和可维护性:对同一类的对象实例化,增加一个类即可,便于维护;代码也比较简洁,增加了可读性
面向对象和接口编程,而不是面向实现编程
2、缺点
违背了“开闭原则”,因为都是在一个工厂的方法中,修改不可避免的要改代码;
简单工厂模式使用静态工厂方法,静态方法不能被继承和重写,不利于继承或者扩展;
3、解决了哪些问题
将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦。
4、应用场景
客户如果只知道传入工厂类的参数(交给客户界面上输入),对于如何创建对象的逻辑不关心时;
当工厂类负责创建的对象(具体产品)比较少时。
登录注册场景
统一支付使用不同支付渠道的场景
六、代码地址
请点击跳转