一、什么是设计模式、为什么要使用它

    对设计模式的解释有很多,在这里我按个人的理解阐述一下。设计模式就是一些常见问题的优秀实践,一套按面向接口严格实现的优秀方法,是经过实践认证的、高效的、解耦的解决方案。那么为什么要使用它,一个设计模式定义了一个问题、定义了一个解决方案、是经过测试的、能促进良好的设计,具有很高的灵活性和可重用性。

二、什么是组合模式

    将一组对象组合为可像单个对象一样被使用的结构。在有些书中说是属性结构,我觉得这个限制太死,只要能灵活的组合多个对象,但并不影响使用效率,并且具有很高的可重用性和灵活性都可以当做组合模式使用。

三、组合模式的具体实践

    我这里有一个场景,一般api之间互相交互数据的时候回需要签名,但不同业务之间签名是不一样的,但签名的原理是一样的,这种情况能否使用组合模式。我这里按组合模式实现了该功能。

<?php
/**
 * 遵循面向接口编程准则
 * Class SignatureInterface
 */

namespace Logic\Signature;

interface SignatureInterface
{
    public function getSecretKey();
}
?>

<?php
/**
 * Service 签名
 * Class ServiceSignature
 */

namespace Logic\Signature;


class ServiceSignatureKey implements SignatureInterface
{
    public $_secretKey  = null;
    public function __construct ()
    {
        $this->_secretKey   = 'Service';
    }

    public function getSecretKey ()
    {
        return $this->_secretKey;
    }
}
?>


<?php
/**
 * SMS 签名
 * Class SmsSignature
 */

namespace Logic\Signature;


class SmsSignatureKey implements SignatureInterface
{
    public $_secretKey  = null;
    public function __construct ()
    {
        $this->_secretKey   = 'EGfAJFp^NGX$kK3!@e7pijEdMOaftwTz';
    }

    public function getSecretKey ()
    {
        return $this->_secretKey;
    }
}
?>


<?php
/**
 * Class ParameterSignature
 * 参数签名类
 */

namespace Logic\Signature;


class ParameterSignature
{
    private $aParams    = null;
    public function __construct (){}
    public function setParam($aParams)
    {
        $this->aParams  = $aParams;
        return $this;
    }

    public function generateSignature(SignatureInterface $oSignature)
    {
        if (empty($this->aParams))
            return false;

        //替换为自己的验签密钥
        $secretKey      = $oSignature->getSecretKey();
        unset($this->aParams['signature']);
        ksort($this->aParams);
        //把所有的值级成字符串
        $paramStr       = implode('', $this->aParams);
        $paramStr       = urlencode($paramStr);
        //签名转为大写字符串
        $signature      = md5(md5($paramStr) . $secretKey);
        $this->aParams['signature'] = strtoupper($signature);
        return $this->aParams;
    }


    public function verifySignature(SignatureInterface $oSignature)
    {
        if (empty($this->aParams))
            return false;

        $getSignature   = isset($this->aParams['signature']) ? $this->aParams['signature'] : null;
        //替换为自己的验签密钥
        $secretKey      = $oSignature->getSecretKey();
        unset($this->aParams['signature']);
        ksort($this->aParams);
        //把所有的值级成字符串
        $paramStr       = implode('', $this->aParams);
        $paramStr       = urlencode($paramStr);
        //签名转为大写字符串
        $signature      = strtoupper(md5(md5($paramStr) . $secretKey));

        return ( $signature == $getSignature ) ? true : false;
    }
}

<?php

/**
 * 业务当中使用
 */
$aParams    = [
    'user_id'   => 1,
    'mobile'    => '15011111111',
    'msg'       => 'Hello,world'
];

//生成签名
$oParameter     = new ParameterSignature();
$oParameter->setParam($aParams);
//初始化要检验的SMS签名类
$oSignature     = new SmsSignatureKey();
//这里可互换
//$oSignature     = new ServiceSignatureKey();
//组合模式生成签名
$aParams        = $oParameter->generateSignature($oSignature);
?>