PHP设计模式-工厂模式

  • 工厂模式

    工厂设计模式提供获取某个对象的新实例的一个接口,同时使调用代码避免确定实际实例化基类的步骤。

    简述:假设,我们现在在获取微信端消息的通知,消息有许多类型,比如文本、图片、语音等,这些类型都包含在微信推送的内容里,需求是要把这些内容都保存在本地的数据库,我们来模拟一下,方法大概有两种:

    微信端消息的通知:用户向某服务号发送信息或触发了一些事件(扫码,上报地理位置等),如果此服务号开启了开发者的一些设置,那么微信会把相关信息或事件推送给服务号设置的接收信息地址。

  1. 获取到微信推送的内容后,判断出信息类型,然后实例化不同的对象来保存对应的信息。
    // 模拟获取信息
    $message = file_get_contents("php://input");
    switch ($message->type) {
        case 'link':
            $object = new Link();
            $object->save($message->content);
            break;
        case 'text':
            $object = new Text();
            $object->save($message->content);
            break;
        case 'image':
            $object = new Image();
            $object->save($message->content);
            break;
        case 'voice':
            $object = new Voice();
            $object->save($message->content);
            break;
        case 'video':
            $object = new Video();
            $object->save($message->content);
            break;
        case 'location':
            $object = new Location();
            $object->save($message->content);
            break;
        default:
            # code...
        break;
    }
    
  2. 使用工厂模式,可以有助于减少主代码流中基于条件的复杂性。
    // 模拟获取信息
    $message = file_get_contents("php://input");
    class MessageFactory {
        public static function create($type) {
            $class = ucfirst(strtolower($type));
    
            return new $class;
        }
    }
    
    $objcet = MessageFactory::create($message->type);
    $object->save($message->content);
    

    可以看到,第二种方式明显比第一种更简洁,不需要做过多的判断。另外,如果微信端增加了新的信息类型,我们在接收时也不需要再增加判断语句,只要增加一个处理对应类型的类即可。

    这种模式有点像硬币自动分拣器一样,不需要每个都判断它是五毛的还是一块的硬币,它会自动去到自己的存放点。见下图:
    硬币自动分拣器

PHP设计模式-建造者模式

  • 建造者模式

    该模式定义了处理其它对象的复杂构建的对象设计。

    简述:是不是很晦涩?没错。现在我们管建造者模式叫榨汁机模式,举个栗子:

    想象现在你有一台榨汁机,榨汁机有十个放入橙子的管道(忽略为什么会有十个管道的梗,我想要一杯大大大橙汁不行么,其实这里类比的意思是:你有需要在十个地方构建同一个对象来使用),当你想得到“一杯橙汁”这个对象时,常规做法,你每次需要:

    1. 从十个入口放入橙子;
    2. 从十个口把去皮的橙子放进去;
    3. 放入一些调味品(比如浓缩橙汁);
    4. 把杯子对准出口,用杯子盛橙汁;
    5. 按动开关,榨汁,得到一杯橙汁.
    

    如果使用榨汁机模式呢?

    1. 从十个入口放入橙子;
    2. 按动开关,榨汁,得到一杯橙汁.
    

    把常规做法下的第2,3,4步全部放入了榨汁机内部,你不用在每个入口处给橙子去皮(这是最重要的),就像你在构建一个对象时,不用每次都给每个对象设置某个属性一样。

    那么问题来了,使用榨汁机模式除了节省了一些构建对象(做出一杯橙汁)步骤之外,还有什么好处呢?
    现在假设你买的橙子都有很多坚硬的籽,如果直接把这些橙子用来榨汁喝会非常影响口感,所以我们需要把籽给去掉,常规做法下:

    1. 给十个橙子去皮;
    2. 给十个橙子去籽(即使是自动去籽也需要在十个入口处加自动去籽机);
    ......
    

    榨汁机模式下,在榨汁机内部增加一个去籽机,然后:

    1. 从十个口放入橙子;
    2. 按动开关,榨汁,得到一杯橙汁.
    

    看出问题了吗?构建对象时,在常规做法下,如果有什么修改,那么在每个构建的地方,都需要去修改。但是在建造者模式下,有了修改,只需要去修改这个构建对象一次即可。

    这就是我理解的建造者模式,如果你有更好的理解,欢迎在下面评论区留言!

PHP设计模式-适配器模式

  • 适配器模式

    将某个对象的接口适配为另一个对象所期望的接口。

    简述:B类在使用A类里的方法,现在C类也需要使用到A类,但又有新特性,怎么办?有两种做法:

    1. 改造A类,增加新方法;
    2. 使用适配器模式,增加一个 A' 类继承A类,把新方法放在 A' 类里,这样C类就直接使用 A' 就好了。
    

    个人生活举例:比如,你有一辆车,你想听音乐(据说开车和听歌更配哟),但车的中控系统里只能播放音乐碟片,这就很尴尬了,手机里有无数好歌,却不能享受,就像你很饿,眼前有盘红烧肉,但吃不到嘴一样。(什么?你说为什么不直接用手机放歌?这是我的设定啊喂!)

    现在也有两个做法:

    1. 大刀阔斧改造中控(拆卸都很麻烦),让她既能播放碟片也能使用蓝牙连接手机;
    2. 买一个蓝牙连接器,通过连线(假设存在这样的线,类似于PHP的继承)连接中控,然后 done。
    

    这就是我理解的适配器模式,如果你有更好的理解,欢迎在下面评论区留言!