工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,
通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品–摘自《百度百科》
前言
写文章的目的主要是为了自己知识的巩固,当然也十分希望在此能够得到业界前辈们的指导。
本篇文章围绕:简单工厂模式、工厂方法模式、抽象工厂模式来大致说明。
设计模式的使用是为了提高代码质量、优雅度以及后期更好的重构项目,如果只是为了实现功能而去编写代码就完全没有这个必要了。当然它的缺点会降低一部分可读性。
场景:某汽车工厂->根据不同订单->生产不同品牌的汽车
1.简单工厂模式(Simple Factory Pattern)
定义:由 一 个 工 厂 对 象 \color{#FF0000}{一个工厂对象} 一个工厂对象决定创建出哪一种产品类的实例。
使用场景:简单工厂模式适用于工厂类对象较少的场景,根据提供的工厂参数来生成不同的产品。无需关心生成过程(new 一个对象的必要条件)
准备工作
//定义一个规范
public interface ICar {
//生产汽车
public void create();
}
//创建一个Audi实现ICar
public class Audi implements ICar {
@Override
public void create() {System.out.println("制造Audi");}
}
//创建一个BMW实现ICar
public class BMW implements ICar {
@Override
public void create() {System.out.println("制造BMW");}
}
以上代码我们在平时开发中也会经常用到,把公共方法单独抽象出一个类,如果按照我们以往的方法就是
public static void main(String[] args) {
//需要一个Audi
ICar icar = new Audi();
icar.create();
//在需要一个BMW
ICar icar1 = new BMW();
icar1.create();
//这样我们每需要一种汽车,我们都需要去单独创建一个对象.如果品种越来越多,
//代码就会变的十分臃肿
}
下面我们使用工厂模式对代码进行优化
1.1 通过类名创建对象
public class CarFactory {
//通过类名创建对象
public ICar create(String name){
if("Audi".equals(name)){
return new Audi();
}else if("BMW".equals(name)){
return new BMW();
}else{//在实际中不建议使用null作为返回值,会造成空指针不必要的麻烦.
return null;
}
}
}
public static void main(String[] args) {
//调用
CarFactory factory = new CarFactory();//创建一个工厂对象
//需要一个Audi
ICar audi = factory.create("Audi");
//需要一个BMW
ICar bmw = factory.create("BMW");
//此类方法根据传入的类名来创建实例,对书写要求较高不允许出现错误。显然不合适
}
1.2通过包名创建对象
public class CarFactory {
//通过类名创建对象
public ICar create(String name){
try {
if(!(null == className ||"".equals(className))){
//通过反射得到类的实例
return (ICar)Class.forName(className).newInstance();
}
}catch (Exception e){
}
return null;
}
}
public static void main(String[] args) {
CarFactory factory = new CarFactory();//创建一个工厂对象
ICar bmw = factory.create("com.xx.BMW")
//此方法通过反射来进行创建,虽然能在一定程度在降低错误,因为我们复制全包名
//的时候往往不会手动输入(- -! 强行解释一波),显然不能解决我们的问题 继续
}
1.3 通过类对象创建实例
public class CarFactory {
//通过类名创建对象
public ICar create(Class cls){
try {
if(cls != null){
//通过反射得到类的实例
return cls.newInstance();
}
}catch (Exception e){
}
return null;
}
}
public static void main(String[] args) {
CarFactory factory = new CarFactory();//创建一个工厂对象
ICar bmw = factory.create(BMW.class)
//你是不是也觉得这样错误率也就大大降低了。
//相较于原始方法是不是在质量上有那么一丢丢提高
}
简单工厂模式
优点:只需传入一个正确合理的参数,就可以获取你所需要的对象 无须知道其创建的过程。
缺点:都由工厂统一创建,工厂类的压力较重,增加新的产品时需要修改工厂类的判断 逻辑,违背开闭原则,不易于扩展相对复杂的结构。
2.工厂方法模式(Factory Method Pattern)
定义:定义一个接口,让实现此接口的类来选择创建哪个类。该工厂不做生产操作,把操作转交给子工厂相当于代理工厂(打个比方:比如富士康帮助苹果生产手机,而苹果本身不生产手机。- - ! 这个比方请不要抬杠)
public interface CarFactory {
//总工厂,将创建逻辑分给代理工厂一对一创建
ICar create();
}
//代理工厂1:生产BMW
public class BMWFactory implements CarFactory{
@Override
public ICar create() {
return new BMW();
}
}
//代理工厂2:生产Audi
public class AudiFactory implements CarFactory{
@Override
public ICar create() {
return new Audi();
}
}
public static void main(String[] args) {
//去Audi工厂要Audi
CarFactory factory = new AudiFactory();
ICar audi = factory.create();
//去BMW工厂要BMW
factory = new BMWFactory();
ICar bmw = factory.create();
}
对工厂方法可以做一些改进:
将CarFactory定义一个抽象类,好处是能添加一些公共的创建条件.
//对工厂方法改进 定义为一个抽象类
public abstract class CarFactory {
//每个方法创建前的逻辑
public void preCreate(){
}
//公共的方法定义成抽象方法
abstract ICourse create();
}
工厂方法模式:
优点:适用于创建对象时需要大量重复的代码
缺点:类的个数较多,复杂度增加,相比第一种抽象了些增加了理解难度。
三、抽象工厂模式(Abastract Factory Pattern)
定义:提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。
什么意思呢?这里解释一下,比方:
1.某一总工厂不单单生产汽车,可能还会生产手机,洗衣机,冰箱等一系列产品。
2.A代理工厂会生产汽车、手机、冰箱、洗衣机。(A生产的产品属于一系列产品 A品牌)
3.B代理工厂会生产汽车、手机、洗衣机。(B生产的产品属于一系列产品 B品牌)
总
工
厂
就
相
当
于
一
个
产
品
类
的
库
,
所
有
的
产
品
对
象
都
从
同
一
个
接
口
出
现
,
\color{#FF0000}{总工厂就相当于一个产品类的库,所有的产品对象都从同一个接口出现,}
总工厂就相当于一个产品类的库,所有的产品对象都从同一个接口出现,
从
而
使
客
户
端
方
面
不
依
赖
与
具
体
实
现
\color{#FF0000}{从而使 客户端方面不依赖与具体实现}
从而使客户端方面不依赖与具体实现
下面请看例子:
//所有的工厂都实现这个工厂,一个品牌的抽象
public interface IFactory {
//制造汽车
ICar Car();
//制造电脑
IComputer computer();
}
//A工厂实现
public class AFactory implements IFactory{
@Override
public ICar Car() {
return new Audi();
}
@Override
public IComputer computer() {
return new DellComputer();
}
}
//B工厂实现
public class BFactory implements IFactory{
@Override
public ICar Car() {
return new Audi();
}
@Override
public IComputer computer() {
return new DellComputer();
}
}
public static void main(String[] args) {
//A工厂 生产A品牌的一系列
IFactory factory = new AFactory();
factory.Car();
factory.computer();
//B工厂 生产B品牌的一系列
IFactory factory1 = new BFactory();
factory1.computer();
factory1.Car();
}
抽象类工厂模式:
优点:扩展性非常强、具体产品在应用层代码隔离,无须关心创建细节、将一个系列的产品统一到一起创建。在spring框架中应该非常广泛
缺点:不符合开闭原则、如果此工厂增加了一个产品,那么所有的子工厂都要实现此方法。
试想一下如果IFactory增加了一个产品,A和B以及更多的子工厂都要实现此类方法。
对本文中
开
闭
原
则
\color{#FF0000}{开闭原则}
开闭原则的补充:
定义:是指一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。所谓的开闭,也正是对扩展和修改两个行为的一个原则。强调的是用抽象构建框架,用实现扩展细节。可以提高软件系统的可复用性及可维护性。开闭原则,是面向对象设计中最基础的设计原则。它指导我们如何建立稳定灵活的系统,例如:我们版本更新,我尽可能不修改源代码,但是可以增加新功能。请看案例
public class Car {
private String name;
private Double price;
private String color;
public Car(String name, Double price, String color) {
this.name = name;
this.price = price;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
定义一个汽车,某一天商场做活动,对汽车打折扣如果我们直接修改getPrice()或setPrice()方法会存在一定的风险,可能会影响到其他地方的调用结果。那么该如何处理?
----另外编写一个类处理此逻辑
public class CarPrice extends Car{
public CarPrice(String name, Double price, String color) {
super(name, price, color);
}
public Double OriginPrice(){
return super.getPrice();
}
public Double getPrice(){
return super.getPrice()*0.5;
}
}
以上三种方式都有适合自己的场景,没有好坏之分,具体根据实际情况选择。
希望各位看过的伙伴们如果发现了问题能够及时批评指正,在此感谢。