PHP设计模式 | 工厂模式

118 阅读5分钟

1.引言

在软件设计中,工厂模式是一种常用的设计模式,它用于创建对象的实例而不暴露实例化对象的具体逻辑。在PHP中,工厂模式有两种常见的实现方式:简单工厂模式和抽象工厂模式。简单工厂模式适用于较为简单的应用场景,而抽象工厂模式则提供了更高的扩展性。在本文中,我们将详细讲解这两种模式,通过实际的PHP代码示例来展示它们的实现方法和应用场景。

2. 核心概念

简单工厂模式(Simple Factory Pattern) :简单工厂模式是通过一个工厂类来创建对象,它根据不同的参数决定实例化哪个类。调用方只需要依赖工厂类,而不需要知道具体的实现类。

抽象工厂模式(Abstract Factory Pattern) :抽象工厂模式比简单工厂模式更加抽象,它通过一组工厂类来创建多个产品类别的对象。每个具体工厂类负责创建一类产品,并且工厂类本身和产品类都遵循抽象化设计,具有很高的可扩展性。

3. 应用场景

简单工厂模式:当创建对象的过程相对简单,且对象类型不多时,适用简单工厂模式。适用于需要选择不同产品类型但不想暴露复杂创建过程的场景。

抽象工厂模式:当系统中存在多个相关产品,并且产品的种类在未来可能会扩展时,使用抽象工厂模式。适用于跨多个产品族的对象创建场景,并且产品类别之间的变动不会影响已有的代码。

4. 实现步骤

1. 简单工厂模式

  • 定义接口:创建一个共同的接口(如 Db 接口),确保所有具体产品类实现该接口。
  • 实现具体产品:实现具体的类(如 Mysql, Oracle)。
  • 工厂类:创建一个工厂类(如 DbFactory),根据输入参数返回不同的产品实例。
/**
 * 定义一个数据库的接口
 */
interface Db {
    /**
     * 定义一个链接数据库的接口方法
     *
     * @return mixed
     * @author kx
     */
    public function conn();
}

// 服务端生产

/**
 * 定义一个mysql数据库实现db的接口
 */
class Mysql implements Db {
    /**
     * 实现链接方法
     *
     * @author kx
     */
    public function conn()
    {
        echo "连接上mysql了";
    }
}

/**
 * 定义一个Oracle数据库
 */
class Oracle implements Db {
    /**
     * 实现链接方法
     *
     * @author kx
     */
    public function conn()
    {
        echo "连接上Oracle了";
    }
}

/**
 * db简单工厂
 */
class DbFactory {
    /**
     * 创建数据库
     *
     * @param $dbType
     * @return Mysql|Oracle
     * @throws Exception
     * @author kx
     */
    public static function createDb($dbType) {
        if ($dbType == "mysql") {
            return new Mysql();
        } elseif ($dbType == "oracle") {
            return new Oracle();
        } else {
            throw new Exception("数据库类型错误");
        }
    }
}

//客户端调用
//只需要调用工厂,传入数据库类型,保证了Mysql、Oracle类不暴露给调用方
$mysql = DbFactory::createDb('mysql');
$mysql->conn();

$mysql = DbFactory::createDb('oracle');
$mysql->conn();

输出内容:

连接上mysql了连接上Oracle了

2. 抽象工厂模式

  • 定义抽象产品接口:创建一个抽象接口(如 Db),定义所有数据库类的共同行为。
  • 定义抽象工厂接口:创建一个工厂接口(如 DbFactory),声明创建产品的方法。
  • 实现具体工厂和产品:创建具体工厂(如 MysqlFactory)和相应的产品类(如 Mysql)。
  • 扩展新产品:如需增加新类型的数据库,只需增加一个新的产品类和工厂类,而不需要修改现有代码。
/**
 * 定义一个数据库的接口
 */
interface Db {
    /**
     * 定义一个链接数据库的接口方法
     *
     * @return mixed
     * @author kx
     */
    public function conn();
}

/**
 * 定义一个数据库工厂接口
 */
interface DbFactory {
    public function createDb();
}

// 服务端生产

/**
 * 定义一个mysql数据库实现db的接口
 */
class Mysql implements Db {
    /**
     * 实现链接方法
     *
     * @author kx
     */
    public function conn()
    {
        echo "连接上mysql了";
    }
}

/**
 * Mysql的工厂类
 */
class MysqlFactory implements DbFactory {
    /**
     * 实现Mysql创建
     *
     * @return Mysql
     * @author kx
     */
    public function createDb()
    {
        return new Mysql();
    }
}

/**
 * 定义一个Oracle数据库
 */
class Oracle implements Db {
    /**
     * 实现链接方法
     *
     * @author kx
     */
    public function conn()
    {
        echo "连接上Oracle了";
    }
}

/**
 * OracleFactory工厂类
 */
class OracleFactory implements DbFactory {
    /**
     * 实现Oracle创建
     *
     * @return Oracle
     * @author kx
     */
    public function createDb()
    {
        return new Oracle();
    }
}

// 新增sqlite,不用修改之前的代码,只需要新增两个类,一个实现Db,一个实现DbFactory

/**
 * 实现Sqlite类
 */
class Sqlite implements Db {
    /**
     * 连接sqlite
     *
     * @author kx
     */
    public function conn()
    {
        echo "连接Sqlite";
    }
}

/**
 * 实现SqliteFactory
 */
class SqliteFactory implements DbFactory {
    /**
     * 实现创建Db方法
     *
     * @return Sqlite
     * @author kx
     */
    public function createDb()
    {
        return new Sqlite();
    }
}

//客户端调用
//需要不同的工厂类,如果需要新增类型,只需要拓展,不需要修改以前的代码
$fac = new MysqlFactory();
$db = $fac->createDb();
$db->conn();

$fac = new OracleFactory();
$db = $fac->createDb();
$db->conn();

$fac = new SqliteFactory();
$db = $fac->createDb();
$db->conn();

输出内容:

连接上mysql了连接上Oracle了连接Sqlite

5. 好处和不足

简单工厂模式

好处

  • 封装性强:客户端无需了解具体对象的创建细节。
  • 易于使用:只需调用工厂类的静态方法即可创建对象,使用简单。

不足

  • 违反开闭原则:每次增加新的数据库类型时,都需要修改工厂类,违反了开闭原则。
  • 不易扩展:随着产品类型的增加,工厂类的代码变得复杂且难以维护。

抽象工厂模式

好处

  • 符合开闭原则:每新增一个产品族,只需要增加对应的工厂类和产品类,无需修改现有代码。
  • 灵活性高:可以根据不同需求创建不同类型的对象,且这些对象是相互兼容的。

不足

  • 实现较复杂:需要定义多个接口和工厂类,相比简单工厂模式,代码更为复杂。
  • 不适用于简单场景:对于简单的对象创建,不需要如此复杂的结构。

6. 总结

简单工厂和抽象工厂模式是两种不同的设计模式,虽然都用于对象的创建,但它们的设计理念和适用场景有所不同。简单工厂模式适用于对象类型较为固定的场景,它实现简单但缺乏灵活性。而抽象工厂模式则为系统的扩展提供了更多的灵活性和可维护性,特别适用于需要创建一系列相互依赖或兼容的对象的场景。

在实际开发中,我们需要根据项目的复杂度、扩展性要求来选择合适的工厂模式。简单工厂可以快速实现一些基础功能,而抽象工厂则在产品种类多、需要扩展时更加合适。