如何使用构造函数参数变化的工厂模式

时间:2016-07-12 21:44:45

标签: php design-patterns

我正在编写一个包,我需要让PHP对象代表MySQL数据类型。

例如,我有IntTypeVarCharTypeBlobType等课程。

每个都有不同的构造函数参数。即IntType有一个已签名的属性,VarChar有整理等等。

我需要从数据库构建这些类型的源代码。所以我可能有" INT(10)UNSIGNED"," VARCHAR(255)"和" BLOB"。

所以目前我有一个检查和拆分这些字符串的方法,它使用大量的IF和SWITCH语句来确定需要构造哪个类。

我知道这很难看,但我不确定最好的方法。 Factory模式的所有教科书示例都基于生成具有相同构造函数参数的类。

目前我有两个想法可以解决这个问题:

  • 使用Chain of Responsibility模式之类的东西,我在每个数据类型都有一个工厂,每个人都会决定它是否可以处理数据类型字符串,如果它不能传递到下一个工厂
  • 每个数据类型都有一个工厂,以及一个检查数据类型字符串的超级工厂,以确定处理字符串的正确数据类型工厂。

因为我没有看到太多关于此的理论,所以我不太了解最理想的方向。

以下是令人讨厌的代码,以显示它是多么丑陋......

<?php

class Factory
{
    // ...

    /**
     * @param string $dataTypeString Data type string as reported by MySQL when executing SHOW FULL COLUMNS FROM table;
     * @param null $collation
     */
    public function createDataType($dataTypeString, $collation = null)
    {
        $dataType = null;

        if (preg_match('/^(tiny|small|medium|big)?int(eger)?\((\d+)\)( unsigned)?/i', $dataTypeString, $matches)) {
            $displayWidth = $matches[3];
            $signed = empty($matches[4]);

            switch (strtolower($matches[1])) {
                case 'tiny':
                    $dataType = new TinyIntType($displayWidth, $signed);
                    break;
                case 'small':
                    $dataType = new SmallIntType($displayWidth, $signed);
                    break;
                case 'medium':
                    $dataType = new MediumIntType($displayWidth, $signed);
                    break;
                case 'big':
                    $dataType = new BigIntType($displayWidth, $signed);
                    break;
                default:
                    $dataType = new IntType($displayWidth, $signed);
                    break;
            }
        } elseif (preg_match('/^(decimal|float|double)\((\d+),(\d+)\)( unsigned)?/i', $dataTypeString, $matches)) {
            $precision = $matches[2];
            $scale = $matches[3];
            $signed = empty($matches[4]);

            switch (strtolower($matches[1])) {
                case 'decimal':
                    $dataType = new DecimalType($precision, $scale, $signed);
                    break;
                case 'double':
                    $dataType = new DoubleType($precision, $scale, $signed);
                    break;
                case 'float':
                    $dataType = new FloatType($precision, $scale, $signed);
            }
        } elseif (preg_match('/^(var)?binary\((\d+)\)$/i', $dataTypeString, $matches)) {
            $isVarBinary = !empty($matches[1]);
            $length = $matches[2];

            if (strtolower($isVarBinary)) {
                $dataType = new VarBinaryType($length);
            } else {
                $dataType = new BinaryType($length);
            }
        } elseif (preg_match('/^bit\((\d+)\)$/i', $dataTypeString, $matches)) {
            $dataType = new BitType($matches[1]);
        } else {
            $characterSet = !empty($collation) ? $this->getCharacterSet($collation) : null;

            if (preg_match('/^(var)?char\((\d+)\)$/i', $dataTypeString, $matches)) {
                $isVarChar = !empty($matches[1]);
                $length = $matches[2];

                if ($isVarChar) {
                    $dataType = new VarCharType($length, $characterSet, $collation);
                } else {
                    $dataType = new CharType($length, $characterSet, $collation);
                }
            } elseif (preg_match("/(set|enum)(\('.+'\))/i", $dataTypeString, $matches)) {
                $options = $this->parseOptions($matches[2]);

                switch (strtolower($matches[1])) {
                    case 'set':
                        $dataType = new SetType($options, $characterSet, $collation);
                        break;
                    case 'enum':
                        $dataType = new EnumType($options, $characterSet, $collation);
                        break;
                }
            } else {
                switch (strtolower($dataTypeString)) {
                    case 'text':
                        $dataType = new TextType($characterSet, $collation);
                        break;
                    case 'tinytext':
                        $dataType = new TinyTextType($characterSet, $collation);
                        break;
                    case 'mediumtext':
                        $dataType = new MediumTextType($characterSet, $collation);
                        break;
                    case 'longtext':
                        $dataType = new LongTextType($characterSet, $collation);
                        break;
                    case 'blob':
                        $dataType = new BlobType();
                        break;
                    case 'tinyblob':
                        $dataType = new TinyBlobType();
                        break;
                    case 'mediumblob':
                        $dataType = new MediumBlobType();
                        break;
                    case 'longblob':
                        $dataType = new LongBlobType();
                        break;
                }
            }
        }

        return $dataType;
    }
}

更新:已在https://codereview.stackexchange.com/questions/134709/a-pattern-to-clean-up-this-factory-method

重新发布

0 个答案:

没有答案