关于设计模式:百度工程师教你玩转设计模式工厂模式

0次阅读

共计 5578 个字符,预计需要花费 14 分钟才能阅读完成。

作者 | 北极星小组

想要写好代码,设计模式(Design Pattern)是必不可少的基本功,设计模式是对面向对象设计(Object Oriented Design)中重复呈现的问题的解决方案,本篇介绍工厂模式(Factory Pattern)。

工厂模式属于创立型模式(Builder Pattern),提供了创建对象的最佳形式,在创建对象时,不会对客户端裸露对象的创立逻辑,而是通过应用独特的接口来创建对象。工厂模式利用的典型场景是,心愿可能创立一个对象,但创立过程比较复杂,心愿对外暗藏这些细节,比方:创建对象可能是一个 pool 里的,不是每次都凭空创立一个新的;对象创立时会有很多参数来决定如何创立出这个对象;创立一个对象有简单的依赖关系。

实现形式上,次要有简略工厂模式(Simple Factory Pattern)、工厂办法模式(Factory Method Pattern)、形象工厂模式(Abstract Factory Pattern)。

一、简略工厂模式在文档解析场景中的利用

在日常开发场景中,如果要创立的产品(被创立的对象类)不多,只有一个工厂类就能够实现,这种模式叫“简略工厂模式”。应用简略工厂模式的客户端(具体调用方)只须要传入须要创立产品类的参数,不须要关怀如何创建对象的逻辑,能够很不便地创立所需产品。

以 Word2007 类型文档解析场景为例:文档主体在 document.xml 文件,解析时依据内容构造维度别离创立 Paragraph、Table、Draw 等具体解析类。在解析流程中,如果间接结构对应解析类的对象应用,则会导致两者的耦合过重,能够应用 “简略工厂模式” 将解析类的理论创立工作推延到工厂类中。这也满足创立型模式中所要求的“创立与应用相拆散”的特点。

具体实现上包含以下几局部:

  • 简略工厂(SimpleFactory):是简略工厂模式的外围,这里负责实现创立所有具体 Parser 实例的外部逻辑。
  • 形象产品(Product):是简略工厂创立的所有对象的父类,这里负责形容所有 Parser 实例共有的公共接口。
  • 具体产品(ConcreteProduct):是简略工厂模式的创立指标,这里负责创立具体的解析类。
public class DocxPaser {    
    // 形象产品:所有 Parser 共有的公共接口
    public interface IPaser {void process(string entity);
    }
    // 具体产品:Paragraph Parser
    static class Paragraph implements IPaser {public void process(string entity) {System.out.println("解析 Paragraph...");
        }
    }
    // 具体产品:Table Parser
    static class Table implements IPaser {public void process(string entity) {System.out.println("解析 Table...");
        }
    }
     // 具体产品:Draw Parser
    static class Draw implements IPaser {public void process(string entity) {System.out.println("解析 Draw...");
        }
    }
    final class Const {
        static final int ENTITY_PARAGRAPHP = 0;
        static final int ENTITY_TABLE      = 1;
        static final int ENTITY_DRAW       = 2;
    }
    
    // 简略工厂:负责实现创立所有具体 Parser 实例的外部逻辑
    static class ParserFactory {public static IPaser creatParser(int kind) {switch (kind) {
                case Const.ENTITY_PARAGRAPHP:
                    return new Paragraph();
                case Const.ENTITY_TABLE:
                    return new Table();
                case Const.ENTITY_DRAW:
                    return new Draw();}
            return null;
        }
    }
    
    // 简略应用示例
    public static void main(String[] args) {
        //entity 对应 document.xml 此处略去具体获取过程
        ...

        // 解析 paragraph
        ParserFactory.creatParser(Const.ENTITY_PARAGRAPHP).process(entity)
        // 解析 table
        ParserFactory.creatParser(Const.ENTITY_TABLE).process(entity)
        // 解析 draw
        ParserFactory.creatParser(Const.ENTITY_DRAW).process(entity)
         
        ...
    }
}

二、工厂办法模式在自动化测试场景的利用

在简略工厂模式中,调用方只须要传入须要创立的对象类参数,就能够取得一个须要的对象,而不必关怀这个对象的具体创立细节。在须要创立的对象类型较少,而且后续不再轻易减少的状况下简略工厂模式即可满足要求。然而针对须要创立的对象品种繁多,而且后续变更较为频繁的场景下,简略工厂模式有两个显著的问题:

  • 因为后续每次新增一种对象都须要批改工厂类中的判断逻辑,违反代码设计中的开闭准则
  • 因为须要对输出的参数进行判断而后初始化适合的类,简略工厂类中 if-else 或者 switch-case 分支过多,代码显得较为臃肿

为了解决以上问题,能够抉择工厂办法模式:定义一个创建对象的接口,而后实现不同对象的创立子类,对象的初始化交由各个工厂的子类去实现。他和简略工厂的区别点在于:

  • 开闭准则:新增对象的状况下,简略工厂模式下须要批改工厂类,而工厂办法模式只须要新增一个工厂的子类去实现新增对象的初始化即可。
  • 代码简洁:简略工厂通过参数抉择并初始化子类,所有工作都由工厂类实现,工厂办法只是定义了一个创建对象的接口,对象的创立放在子类去实现。

以前端浏览器自动化测试的场景为例,在不同的浏览器场景下必须通过对应的浏览器驱动能力实现测试的执行,例如常见的 Chrome、Firefox、Safari、IE 浏览器。这个场景就能够通过工厂办法模式来进行实现。首先是定义场景下的驱动对象,Driver 为各个具体驱动须要继承的抽象类,其余的 XDriver 为具体某个浏览器的驱动对象。接下来定义对应的形象工厂并实现不同对象初始化的工厂子类,AbstractFactory 为形象工厂,定义了创立驱动对象的接口,其余的每个工厂实现了形象工厂的接口,并提供对应驱动的初始化能力。最初理论的使用者依据须要抉择某个工厂类即可实现对应的驱动初始化工作。

public class FactoryDemo {

    // 形象对象:所有驱动对象的公共父类
    abstract static class Driver {abstract void process();
    }

    // 具体驱动对象:Chrome 浏览器驱动对象
    static class ChromeDriver extends Driver {
        @Override
        void process() {System.out.println("ChromeDriver process"); // do something
        }
    }

    // 具体驱动对象:Firefox 浏览器驱动对象
    static class FirefoxDriver extends Driver {
        @Override
        void process() {System.out.println("FirefoxDriver process"); // do something
        }
    }

    // 具体驱动对象:Safari 浏览器驱动对象
    static class SafariDriver extends Driver {
        @Override
        void process() {System.out.println("SafariDriver process"); // do something
        }
    }

    // 形象工厂 所有工厂的公共接口
    public interface AbstractFactory {Driver create();
    }

    // 具体工厂:负责 Chrome 浏览器驱动对象的创立
    static class ChromeDriverFactory implements AbstractFactory {
        @Override
        public Driver create() {return new ChromeDriver();
        }
    }

    // 具体工厂:负责 Firefox 浏览器驱动对象的创立
    static class FirefoxDriverFactory implements AbstractFactory {
        @Override
        public Driver create() {return new FirefoxDriver();
        }
    }

    // 具体工厂:负责 Safari 浏览器驱动对象的创立
    static class SafariDriverFactory implements AbstractFactory {
        @Override
        public Driver create() {return new SafariDriver();
        }
    }

    public static void main(String[] args) {
        // 创立 Chrome 驱动对象
        AbstractFactory chromeDriverFactory = new ChromeDriverFactory();
        Driver chromeDriver = chromeDriverFactory.create();
        chromeDriver.process();

        // 创立 Firefox 驱动对象
        AbstractFactory firefoxDriverFactory = new FirefoxDriverFactory();
        Driver firefoxDriver = firefoxDriverFactory.create();
        firefoxDriver.process();

        // ...
    }
}

三、形象工厂模式在跨端场景下的利用

形象工厂模式,是对工厂办法模式的进一步深入,工厂办法模式中只有一个形象办法,要想实现多种不同的类对象,只能去创立不同的具体工厂办法的子类来实列化,而形象工厂则是让一个工厂负责创立多个不同类型的对象。

以典型的跨端场景为例,用户可购买会员有多种类型,每种类型的会员在 iOS、Android、PC 下权利页稍有不同,并且实例化过程十分复杂。如果不必工厂模式,就须要在每处须要实例的中央,去编写简单的实例化代码,当实例化过程产生批改,也须要每处批改,保护老本十分高。如果用简略工厂模式或者工厂办法模式,不必形象工厂模式,就须要每个类型会员实现三个工厂,也不易于保护。

在这个场景下,咱们能够用形象工厂模式解决,编写形象工厂、会员抽象类,并实现 iOS、Android、PC 三个具体工厂,依据场景选取须要的具体工厂获取会员实例。

// 形象产品
public interface Vip {}

// 具体产品
public class NormalVip implements Vip {} // 一般会员
public class MonthlyVip implements Vip {} // 包月会员

public class IOSNormalVip extends NormalVip {}
public class AndroidNormalVip extends NormalVip {}
public class PCNormalVip extends NormalVip {}

public class IOSMonthlyVip extends MonthlyVip {}
public class AndroidMonthlyVip extends MonthlyVip {}
public class PCMonthlyVip extends MonthlyVip {}

// 形象工厂
public interface AbstractVipFactory {Vip createNormalVip();
    Vip createMonthlyVip();}

// 具体工厂
public class IOSVipFactory implements AbstractVipFactory {
    @Override
    public Vip createNormalVip() {return new IOSNormalVip();
    }
    
    @Override
    public Vip createMonthlyVip() {return new IOSMonthlyVip();
    }
}
...

// 调用示例
public class Client {public static void main(String[] args) {IOSVipFactory iosVipFactory = new IOSVipFactory();
        Vip iosNormalVip = iosVipFactory.createNormalVip();}
}

四、总结

通过对以上三个理论案例的解说和具体的代码实现浏览,大家对工厂模式的利用场景和具体实现计划应该有了更加深刻的理解了。联合以上三个案例的的剖析,创立过程简单时,适宜应用工厂模式,罕用的工厂模式有:

  • 简略工厂模式:实例化过程简单时,能够选用
  • 工厂办法模式:产品构造较简单时,能够选用
  • 形象工厂模式:产品种类构造多时,能够选用

———- END ———-

举荐浏览【技术加油站】系列:

揭秘百度智能测试在测试剖析畛域实际

百度用户产品流批一体的实时数仓实际

ffplay 视频播放原理剖析

百度工程师眼中的云原生可观测性追踪技术

应用百度开发者工具 4.0 搭建专属的小程序 IDE

百度工程师教你玩转设计模式(观察者模式)

正文完
 0