设计模式之 工厂模式

工厂设计模式又分为简单工厂模式,工厂方法模式,抽象工厂模式

简单工厂模式 : 简单工厂模式是属于创建型的设计模式,又叫做静态工厂方法模式,但不属于23种GOF设计模式,简单工厂模式是由一个工厂决定创建哪一类产品的实例,简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

<?php
/**
 * 简单工厂模式
 */
interface IDB{
    public function connect();
    public function query();
}

class Mysql implements IDB{
    public function connect(){
        echo "连接mysql\n";
    }
    
    public function query(){
        echo "查询mysql\n";
    }
}

class SqlServer implements IDB{
    public function connect(){
        echo "连接sqlserver\n";
    }
    
    public function query(){
        echo "查询sqlserver\n";
    }
}

class DbFactory{
    public static $instance = null;
    public static function Create($dbname){
        switch($dbname){
            case 'mysql':
                self::$instance =  new Mysql();
                break;
            case 'sqlserver' : 
                self::$instance =  new SqlServer();
        }
        return self::$instance;
    }
}

class Client{
    public static  function main(){
        $db = DbFactory::Create('mysql');
        $db->connect();
        $db->query();
        
        $db = DbFactory::Create('sqlserver');
        $db->connect();
        $db->query();
    }
}
Client::main();

我们可以看到简单工厂设计模式包含了3个角色,IDB接口(抽象产品),Sqlserver类(具体产品类),Mysql类(具体产品类),工厂方法类

客户端无需关心sqlserver或者Mysql对象的过程,只需要调用工厂方法传入参数获取实例,参数可以定义为常量,当需要切数据库的时候,只需要增加对应数据库类,修改常量即可。如果客户端自己new,想想切库的感觉那叫一个酸爽。

优点: 对客户端隐藏了对象实例化细节,去除了客户端与具体的产品类之间的依赖

缺点:

  1.当需要增加新的产品时,需要修改工厂方法,违背了开闭原则(当然我们可以利用反射去创建对象,无需修改工厂方法,PHP甚至反射都不需要,直接通过变量创建对象)

  2.当产品很多时工厂方法逻辑会过于复杂

使用场景:

简单工厂模式适用客户端不用知道具体的产品类,只需要知道工厂方法类的情况,但是只适合创建少量的产品。

工厂方法模式:定义一个用于创建对象的接口,让子类决定将哪一个类实例化,工厂方法模式让一个类的实例化延迟到其子类

简单工厂模式在新增产品的时候需要修改工厂方法创建对象的逻辑,违反了开放封闭原则,根据依赖倒转原则,把工厂类抽象出一个接口,这个接口有一个create()方法,然后具体的工厂类实现这个接口,客户端调用对应的工厂方法就能得到需要的产品。

<?php
/**
 * 工厂方法模式
 */
interface IDB{
    public function connect();
    public function query();
}

interface IDbFactory{
    public function create();
}

class Mysql implements IDB{
    public function connect(){
        echo "连接mysql\n";
    }
    
    public function query(){
        echo "查询mysql\n";
    }
}

class SqlServer implements IDB{
    public function connect(){
        echo "连接sqlserver\n";
    }
    
    public function query(){
        echo "查询sqlserver\n";
    }
}

class MysqlFatory implements IDbFactory{
    public function create(){
        return new Mysql();
    }
}

class SqlServerFatory implements IDbFactory{
    public function create(){
        return new SqlServer();
    }
}

class Client{
    public static  function main(){
        $dbFactory = new MysqlFatory();
        $db = $dbFactory->create();
        $db->connect();
        $db->query();
        
        $dbFactory = new SqlServerFatory();
        $db = $dbFactory->create();
        $db->connect();
        $db->query();
    }
}
Client::main();

通过UML图我们可以看到工厂方法模式比简单工厂模式多了一个抽象工厂接口的角色,这个角色起所起到的作用就是使得简单工厂模式里工厂方法针对接口编程,而不是针对具体生成对象细节编程。这样以后新增了Orace数据库的时候只需要新增Oracle类和工厂方法类。

完全做到了对修改关闭。

优点 :除了拥有简单工厂对客户端隐藏了对象创建细节的优点外,工厂方法模式在新增产品的时候只需新增具体的产品类以及工厂方法类,做到了对修改关闭,不影响现有的业务逻辑

缺点 : 每次增加产品都要新增产品类,工厂方法类,造成系统复杂度越来越高

抽象工厂模式:提供一个创建一系列相关的或者相互依赖对象的接口,而无需指定它们具体的类

<?php
/**
 * 抽像工厂模式
 */
interface IDB{
    public function connect();
    public function query();
}

interface ICache{
    public function connect();
    public function get();
}

interface IFactory{
    public function creatDB();
    public function createCache();
}

class Mysql implements IDB{
    public function connect(){
        echo "连接mysql\n";
    }
    
    public function query(){
        echo "查询mysql\n";
    }
}

class SqlServer implements IDB{
    public function connect(){
        echo "连接sqlserver\n";
    }
    
    public function query(){
        echo "查询sqlserver\n";
    }
}

class MysqlCache implements ICache{
    public function connect(){
        echo "连接mysql缓存\n";
    }
    
    public function get(){
        echo "查询mysql缓存\n";
    }
}

class SqlServerCache implements ICache{
    public function connect(){
        echo "连接sqlserver缓存\n";
    }
    
    public function get(){
        echo "查询sqlserver缓存\n";
    }
}


class MysqlFatory implements IFactory{
    public function creatDB(){
        return new Mysql();
    }
    
    public function createCache() {
        return new MysqlCache();
    }
}

class SqlServerFatory implements IFactory{
    public function creatDB(){
        return new SqlServer();
    }
    
    public function createCache() {
        return new SqlServerCache();
    }
}


class Client{
    public static  function main(){
        $factory = new MysqlFatory();
        $db = $factory->creatDB();
        $db->connect();
        $db->query();
        
        $cache = $factory->createCache();
        $cache->connect();
        $cache->get();
        
        $factory = new SqlServerFatory();
        $db = $factory->creatDB();
        $db->connect();
        $db->query();
        
        $cache = $factory->createCache();
        $cache->connect();
        $cache->get();
    }
}
Client::main();

我们通过类图可以看到抽象工厂方法模式和工厂方法模式唯一的区别是产品接口里不仅仅只有一个方法,而是一系列方法,原先我们只能创建db实例,现在也可以创建cache实例,抽象工厂模式解决了工厂方法模式只能创建1系列产品的缺点,

但是新增一个产品系列需要修改抽象产品接口,具体的工厂类。

优点:除了隐藏对象创建细节,还可以创建多种系列的产品

缺点:增加新系列产品,需要需改抽象接口以及具体的工厂类

可能是我项目经验不够,实际项目中我们用的最多的就是简单工厂模式了,其它两种基本没用到过,简单工厂模式配合PHP变量创建对象即可消除其违反开闭原则的缺点。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序你好

最近我遇到的10个Java面试问题

最近,我参加了一些java的面试。突然,我有了一个想法,我想和大家分享我的经历。我希望我能通过分享我最近几个月遇到的10个Java面试问题来帮助大家。

963
来自专栏Petrichor的专栏

tensorflow编程: Building Graphs

每次都必须要指定一个graph作为as_default,并只能在该graph中进行一切操作。

1493
来自专栏walterlv - 吕毅的博客

.NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)

发布于 2018-09-02 14:27 更新于 2018-09...

6991
来自专栏锦小年的博客

python学习笔记7.4-内建模块base64

有时候,我们用noepad++或者记事本打开图片或者程序等文件的时候会显示大量的乱码,主要原因是这些文件编码的时候并不是字符串编码的。如果我们想把这些文件正常显...

2269
来自专栏向治洪

python 日期与时间

###python 日期与时间 (time,datetime包) [toc] #####概述 在应用程序的开发过程中,难免要跟日期、时间处理打交道。如:记录一个...

41810
来自专栏java一日一条

在Java中如何避免“!=null”式的判空语句?

我整天都是在跟Java打交道。我在Java开发中最常用的一段代码就是用object != null在使用对象之前判断是否为空。这么做是为了避免NullPoint...

2471
来自专栏逸鹏说道

必备 .NET - C# 异常处理

欢迎查看首个“必备.NET”专栏。您可以在其中了解 Microsoft .NET Framework 领域的所有最新动态,无论是 C# vNext 的最新进展(...

2836
来自专栏达摩兵的技术空间

js代码优化日常001

本文开始针对项目中总结出来的关于js基础知识的代码优化技巧进行每个细节点的分析,后续还会针对某个专题的分析。

1873
来自专栏做全栈攻城狮

程序员带你十天快速入门Python,玩转电脑软件开发(四)

本系列文章立志于从一个已经习得一门编程语言的基础之上,全面介绍Python的相关开发过程和相关经验总结。本篇文章主要是基于上一篇的程序员带你十天快速入门Pyth...

932
来自专栏java一日一条

10个惊艳的Swift单行代码

几年前,一篇表述“10个Scala函数式单行代码”的文章非常受欢迎,并且随后立马出现了其他的语言版本,例如Haskell版本,Ruby版本,Groovy版本,C...

962

扫码关注云+社区

领取腾讯云代金券