设计模式简单工厂模式和工厂方法模式

56次阅读

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

工厂模式是常用的模式之一(那是相当重要~),它属于创建类型,通过“工厂”的字面意思也可以看出来工厂负责生产产品,顾客只需要关注产品就行了,不需要关注产品的生产过程。这样做的好处就是降低顾客和产品之间的耦合度、提高了代码的复用率。

工厂模式分为 :简单工厂模式、工厂方法模式、抽象工厂模式。

简单工厂模式 :就是简单的只生产一种产品,你想要其他产品,那不好意思,我生产不了,只能最基本的解决顾客和工厂之间的耦合问题。

具体的代码逻辑:利用静态方法创建对象。

工厂方法模式 :在简单工厂的基础上,可以生产同种类型多种产品,但是不能为该产品增加新的特性(因为不符合开闭原则)。

具体的代码逻辑:去掉简单工厂模式中创建对象的静态方法,定义创建工厂的接口(基类),具体的工厂可以实现(或继承)该工厂接口(或基类),同时定义产品的接口(或基类),具体的产品可以实现(或继承)该产品接口(基类),工厂实际生产什么产品交给具体的工厂类和具体的产品类。这样我们增加新的同种类产品工厂,但是不能为产品增加新的特性(因为不符合开闭原则)。

抽象工厂模式 :不同的工厂可以生产相同属性的不同的产品,但是不能生产没有报备的新产品(因为不符合开闭原则)。

具体代码逻辑:提供了创建工厂的接口,该接口里面需要声明工厂可以生产哪些产品,同时提供了创建这些产品的接口,该接口里面需要声明该产品的属性,这样可以实现具体的工厂可以在现有产品的基础上进行升级和改造,但是不能生产没有声明的新产品(因为不符合开闭原则)。

举例:
我要艺术作品生产商,我想把我手里的电影作品(包含艺术家和作品名称)给生产出来。嗯,需求简单,那就用简单工厂模式,老规矩上代码:

class MovieFactory
{
    /**
     * 生产电影
     *
     * @return MovieProduction
     */
    public function generateMovie()
    {return new MovieProduction();
    }
}

我们创建一个电影工厂来生产电影作品。

class MovieProduction
{
    // 艺术家
    protected $_artist     = null;
    
    // 作品名
    protected $_production = null;
    
    /**
     * 设置艺术家
     *
     * @param double $num 数字
     * @return void
     */
    public function setArtist($name)
    {$this->_artist = $name;}
    
    /**
     * 获取艺术家
     *
     * @return null
     */
    public function getArtist()
    {return $this->_artist;}
    
    /**
     * 设置作品
     *
     * @param null $production
     */
    public function setProduction($production)
    {$this->_production = $production;}
    
    /**
     * 获取作品
     *
     * @return null
     */
    public function getProduction()
    {return $this->_production;}
    
    /**
     * 获取作品
     *
     * @return string 字符串
     */
    public function getMovie()
    {return '来自' . $this->_artist . '的电影作品:《' . $this->_production  . '》';}
}

电影作品包含艺术家(artist)和作品(production)两个信息。还提供一个直接获取产品的方法 getMovie.

具体的调用:

// 创建电影工厂
$movie_factory = new MovieFactory();

// 电影工厂生产电影
$movie         = $movie_factory->generateMovie();

// 设置电影的艺术家
$movie->setArtist('张三');

// 设置电影的名称
$movie->setProduction('张三的电影');

// 获取电影昌平
echo $movie->getMovie() . "\r\n";

结果:
来自张三的电影作品:《张三的电影》

简单工厂简单吧。

经过一段时间的生产来看,我觉电影的产出不错,这时候我还想把我手里的音乐作品给生产出来,如果用简单工厂来,我需要创建一个音乐工厂来生产音乐产品。又经过一段时间,我想生产动漫,我需要创建一个动漫工厂来生产动漫。又经过。。。。。。

最后

工厂卒!!!

这时候工厂会想,每次都需要折腾一遍,太累了,我需要想个高效的方法,这样每次要生产类似的新产品的时候,我只用考虑产品的最后的生产就行了,不用考虑工厂的创建问题。

有,来看下工厂方法模式:

interface ArtFactory
{
    /**``
     * 产生艺术
     *
     * @return mixed
     */
    public function gererateArt();}

我们首先来创建一个工厂接口(当然抽象的基类也可以),这个里面方法负责具体生产什么产品,而不用关心工厂的创建。

接下来生产电影:

class MovieFactory implements ArtFactory
{
    /**
     * 形成电影艺术
     *
     * @return mixed
     */
    public function gererateArt()
    {// TODO: Implement createOperate() method.
        return new MovieProduction();}
}

具体的工厂类负责具体的产品实现。

我们还需要创建一个类似产品的流水线,这时候我们创建一个产品的基类,


class ArtProduction
{
    // 艺术家
    protected $_artist     = null;
    
    // 作品名
    protected $_production = null;
    
    /**
     * 设置艺术家
     *
     * @param double $num 数字
     * @return void
     */
    public function setArtist($name)
    {$this->_artist = $name;}
    
    /**
     * 获取艺术家
     *
     * @return null
     */
    public function getArtist()
    {return $this->_artist;}
    
    /**
     * 设置作品
     *
     * @param null $production
     */
    public function setProduction($production)
    {$this->_production = $production;}
    
    /**
     * 获取作品
     *
     * @return null
     */
    public function getProduction()
    {return $this->_production;}
    
    /**
     * 获取作品
     *
     * @return string 字符串
     */
    public function getArt()
    {return '';}
}

具体的产品只关心最后的产出就行了,

class MovieProduction extends ArtProduction
{
    /**
     * 获取艺术
     *
     * @return float|string|null
     */
    public function getArt()
    {return '来自' . $this->_artist . '的电影作品:《' . $this->_production  . '》';}
}

具体的调用过程:

// 创建电影工厂
$movie_factory = new MovieFactory();

// 电影工厂生产电影
$movie         = $movie_factory->gererateArt();

// 设置电影的艺术家
$movie->setArtist('张三');

// 设置电影的名称
$movie->setProduction('张三的电影');

// 获取电影昌平
echo $movie->getArt() . "\r\n";

最后的执行结果:

来自张三的电影作品:《张三的电影》

这个时候,我们要是增加一个音乐的生产,也只是增加一个音乐工厂,音乐产品就行,这样实现了开闭原则。

采用新模式之后,工厂的生产效率提高了 1000%。

今天我们先说这么多,下一篇我们说一下工厂模式中的抽象工厂模式。

正文完
 0