一般地,很多技术人员在工作前期,很少关注代码结构,每次来一个需求,就是在现有代码的基础上增加新代码实现,这样并没有错,只不过长久下去,会导致代码的可维护性非常差(项目中,大函数常常遇到),比如,一个项目交接多次后,很多的业务逻辑很难梳理清楚,为了增加代码的可维护性,那么应该怎么办呢?方法很多,比如项目架构合理设计、代码设计模式的使用、以及多系统间交互等等。都可以提高代码的质量,本文将详细分析一下
工厂模式(Factory Pattern)
。
1. 目的
旨在提供一种最佳的对象创建方式,解耦和复用
2. 分类
简单工厂、工厂方法、抽象工厂
3. 场景
以不同厂商生产鼠标为例
#利用集成实现子类
abstract class Mouse
{
public function click();
}
class HpMouse extends Mouse
{
public function click()
{
echo "hp mouse click!";
}
}
class LogiMouse extends Mouse
{
public function click()
{
echo "logitech mouse click!";
}
}
3.1 简单工厂
class MouseFactory
{
public static function createMouse($type)
{
switch(strtolower($type)) {
case 'hp':
return new HpMouse();
case 'logitech':
return new LogiMouse();
default:
return '';
}
}
}
#使用
hpm = MouseFactory::createMouse('hp');
lgm = MouseFactory::createMouse('logitech');
当有新的鼠标生产商出现时,需要创建新的
Mouse
类和修改MouseFactory
类,违反开闭原则
3.2 工厂方法
为了解决不修改FactoryMouse类的问题,将工厂抽象,即每个厂家都有自己的工厂,如需调整,互不影响,解决开闭原则问题。
interface MouseFactory
{
public static function createMouse();
}
class HpMouseFactory implement MouseFactory
{
public static function createMouse()
{
return new HpMouse();
}
}
class LogiMouseFactory implement MouseFactory
{
public static function createMouse()
{
return new LogiMouse();
}
}
工厂方法,当有新的厂商时,需要新建对应的Mouse和Factory类,都是新增,避免了修改,例如增加一个lemon的厂商,需要新增如下类:
class LemonMouse extends Mouse
{
public function click()
{
echo 'lemon click';
}
}
class LemonFactory implement MouseFactory
{
public static function createMouse()
{
return new LemonMouse();
}
}
3.3. 抽象工厂
工厂方法解决了简单工厂的修改问题,让代码更加解耦,现在是只能生产鼠标,如果要配套生产键盘,就需要全部进行修改,那怎么办呢?这就需要抽象工厂进行解决,这也是对Factory进行抽象。
abstract class Keyboard{}
class HpKeyboard extends Keyboard{}
class LogiKeyboard extends Keyboard{}
interface IFactory
{
public static function CreateMouse();
public static function CreateKeyboard();
}
class HpFactory implement IFactory
{
public static function CreateMouse()
{
return new HpMouse();
}
public static function CreateKeyboard()
{
return new HpKeyboard();
}
}
class LogiFactory implement IFactory
{
public static function CreateMouse()
{
return new LogiMouse();
}
public static function CreateKeyboard()
{
return new LogiKeyboard();
}
}
当有新的厂商lemon时,需要实现相关的鼠标、键盘类、工厂类,同样满足开闭原则。
注意:可以看出,当抽象的层次越高,开发量越大,文件越多,但结构更加清晰明了,所以有利有弊,任何一种模式,只要被合适的场景下使用,就是好的代码实践,切勿为了使用而使用。