工厂模式是常用的模式之一(那是相当重要~),它属于创建类型,通过“工厂”的字面意思也可以看出来工厂负责生产产品,顾客只需要关注产品就行了,不需要关注产品的生产过程。这样做的好处就是降低顾客和产品之间的耦合度、提高了代码的复用率。
工厂模式分为:简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂模式:就是简单的只生产一种产品,你想要其他产品,那不好意思,我生产不了,只能最基本的解决顾客和工厂之间的耦合问题。
具体的代码逻辑:利用静态方法创建对象。
工厂方法模式:在简单工厂的基础上,可以生产同种类型多种产品,但是不能为该产品增加新的特性(因为不符合开闭原则)。
具体的代码逻辑:去掉简单工厂模式中创建对象的静态方法,定义创建工厂的接口(基类),具体的工厂可以实现(或继承)该工厂接口(或基类),同时定义产品的接口(或基类),具体的产品可以实现(或继承)该产品接口(基类),工厂实际生产什么产品交给具体的工厂类和具体的产品类。这样我们增加新的同种类产品工厂,但是不能为产品增加新的特性(因为不符合开闭原则)。
抽象工厂模式:不同的工厂可以生产相同属性的不同的产品,但是不能生产没有报备的新产品(因为不符合开闭原则)。
具体代码逻辑:提供了创建工厂的接口,该接口里面需要声明工厂可以生产哪些产品,同时提供了创建这些产品的接口,该接口里面需要声明该产品的属性,这样可以实现具体的工厂可以在现有产品的基础上进行升级和改造,但是不能生产没有声明的新产品(因为不符合开闭原则)。
举例:
我要艺术作品生产商,我想把我手里的电影作品(包含艺术家和作品名称)给生产出来。嗯,需求简单,那就用简单工厂模式,老规矩上代码:
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%。
今天我们先说这么多,下一篇我们说一下工厂模式中的抽象工厂模式。