博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
最简单易懂的设计模式——工厂模式
阅读量:4078 次
发布时间:2019-05-25

本文共 4512 字,大约阅读时间需要 15 分钟。

最简单易懂的设计模式之工厂模式

工厂模式

前言

在编程中,构建对象最常用的方式是 new 一个对象。其实构建过程可以被封装起来,工厂模式便是用于封装对象的设计模式。

简单工厂模式

比如,直接 new 对象的方式相当于当我们需要一个苹果时,我们需要知道苹果的构造方法,需要一个梨子时,需要知道梨子的构造方法。更好的实现方式是有一个水果工厂,我们告诉工厂需要什么种类的水果,水果工厂将我们需要的水果制造出来给我们就可以了。这样我们就无需知道苹果、梨子是怎么种出来的,只用和水果工厂打交道即可。

水果工厂代码:

public class FruitFactory {        public Fruit create(String type) {            switch (type) {                case "apple":                    return new Apple();                case "pear":                    return new Pear();                default:                    throw new IllegalArgumentException("do not have this fruit!");            }        }}

调用者代码:

public class User {        private void eat() {            FruitFactory fruitFactory = new FruitFactory();            Fruit apple = fruitFactory.create("apple");            Fruit pear = fruitFactory.create("pear");            apple.eat();            pear.eat();        }}

将构建过程封装的好处不仅可以降低耦合,如果某个产品构造方法相当复杂,使用工厂模式可以大大减少代码重复。比如,如果生产一个苹果需要苹果种子、阳光、水分,将工厂修改如下:

public class FruitFactory {        public Fruit create(String type) {            switch (type) {                case "apple":                    AppleSeed appleSeed = new AppleSeed();                    Sunlight sunlight = new Sunlight();                    Water water = new Water();                    return new Apple(appleSeed, sunlight, water);                case "pear":                    return new Pear();                default:                    throw new IllegalArgumentException("do not have this fruit!");            }        }}

调用者的代码则完全不需要变化,而且调用者不需要在每次需要苹果时,自己去构建苹果种子、阳光、水分以获得苹果。苹果的生产过程再复杂,也只是工厂的事。这就是封装的好处,假如要将肥料加入苹果的生产过程中的话,也只需要在工厂中修改。

简单工厂模式就是让一个工厂类承担构建所有对象的职责。调用者需要什么产品,让工厂生产出来即可。它的弊端:

1、如果需要生产的产品过多,此模式会导致工厂类过于庞大,承担过多的职责,变成超级类。当苹果生产过程需要修改时,要来修改此工厂。梨子生产过程需要修改时,也要来修改此工厂。也就是说这个类不止一个引起修改的原因。违背了单一职责原则。

2、当要生产新的产品时,必须在工厂类中添加新的分支。而开闭原则告诉我们:类应该对修改封闭。我们希望在添加新功能时,只需增加新的类,而不是修改既有的类,所以这就违背了开闭原则。

工厂方法模式

为了解决简单工厂模式的这两个弊端,工厂方法模式应运而生,它规定每个产品都有一个专属工厂。比如苹果有专属的苹果工厂,梨子有专属的梨子工厂,代码如下:

public class AppleFactory {        public Fruit create() {            return new Apple();        } }
public class PearFactory {        public Fruit create() {            return new Pear();        } }

调用者代码:

public class User {        private void eat() {            AppleFactory appleFactory = new AppleFactory();            Fruit apple = appleFactory.create();            PearFactory pearFactory = new PearFactory();            Fruit pear = pearFactory.create();            apple.eat();            pear.eat();        }}

当构建过程相当复杂时,工厂将构建过程封装起来,调用者可以很方便的直接使用,举个栗子:

public class AppleFactory {        public Fruit create() {            AppleSeed appleSeed = new AppleSeed();            Sunlight sunlight = new Sunlight();            Water water = new Water();            return new Apple(appleSeed, sunlight, water);        }}

调用者无需知道苹果的生产细节,当生产过程需要修改时也无需更改调用者。同时,工厂方法模式解决了简单工厂模式的两个弊端:

1、当生产的产品种类越来越多时,工厂类不会变成超级类。工厂类会越来越多,保持灵活。不会越来越大、变得臃肿。如果苹果的生产过程需要修改时,只需修改苹果工厂。梨子的生产过程需要修改时,只需修改梨子工厂。符合单一职责原则。

2、当需要生产新的产品时,无需更改既有的工厂,只需要添加新的工厂即可。保持了面向对象的可扩展性,符合开闭原则。

抽象工厂模式

工厂方法模式可以进一步优化,提取出工厂接口:

public interface IFactory {        Fruit create();}

分别实现此接口:

public class AppleFactory implements IFactory {        @Override        public Fruit create() {            return new Apple();        }}
public class PearFactoryimplements IFactory {        @Override        public Fruit create() {            return new Pear();        }}

调用者可以将 AppleFactory 和 PearFactory 统一作为 IFactory 对象使用,代码如下:

public class User {        private void eat() {            IFactory appleFactory = new AppleFactory();            Fruit apple = appleFactory.create();            IFactory pearFactory = new PearFactory();            Fruit pear = pearFactory.create();            apple.eat();            pear.eat();        }}

可以看到,我们在创建时指定了具体的工厂类后,在使用时就无需再关心是哪个工厂类,只需要将此工厂当作抽象的 IFactory 接口使用即可。这种经过抽象的工厂方法模式被称作抽象工厂模式。

由于客户端只和 IFactory 打交道了,调用的是接口中的方法,使用时根本不需要知道是在哪个具体工厂中实现的这些方法,这就使得替换工厂变得非常容易。举个栗子:

public class User {        private void eat() {            IFactory factory = new AppleFactory();            Fruit fruit = factory.create();            fruit.eat();        }}

如果要替换,只需要修改一行,修改对应的工厂即可:

public class User {        private void eat() {            IFactory factory = new PearFactory();            Fruit fruit = factory.create();            fruit.eat();        }}

IFactory 中只有一个抽象方法时,或许还看不出抽象工厂模式的作用。实际上抽象工厂模式主要用于替换一系列方法。

抽象工厂模式很好的发挥了开闭原则、依赖倒置原则,但缺点是抽象工厂模式太重了,如果 IFactory 接口需要新增功能,则会影响到所有的具体工厂类。使用抽象工厂模式,替换具体工厂时只需更改一行代码,但要新增抽象方法则需要修改所有的具体工厂类。所以抽象工厂模式适用于增加同类工厂这样的横向扩展需求,不适合新增功能这样的纵向扩展。

转载地址:http://nzsni.baihongyu.com/

你可能感兴趣的文章
【leetcode】Sum Root to leaf Numbers
查看>>
如何成为编程高手
查看>>
本科生的编程水平到底有多高
查看>>
从mysql中 导出/导入表及数据
查看>>
HQL语句大全(转)
查看>>
几个常用的Javascript字符串处理函数 spilt(),join(),substring()和indexof()
查看>>
layui插件的使用
查看>>
9、VUE面经
查看>>
Golang 数据可视化利器 go-echarts ,实际使用
查看>>
mysql 跨机器查询,使用dblink
查看>>
Oracle 异机恢复
查看>>
Oracle 12C DG 搭建(RAC-RAC/RAC-单机)
查看>>
Truncate 表之恢复
查看>>
为什么很多程序员都选择跳槽?
查看>>
Jenkins + Docker + SpringCloud 微服务持续集成 - 单机部署(二)
查看>>
C#控件集DotNetBar安装及破解
查看>>
Winform多线程
查看>>
C# 托管与非托管
查看>>
Node.js中的事件驱动编程详解
查看>>
mongodb管理与安全认证
查看>>