2

私のコントロールクラスは基本的に、インスタンス化するオブジェクト/クラスを選択します。これは基本的にそれが行うことであるため、それは自然にそれが呼び出す多くのオブジェクト/クラスを持っています。

依存性注入を使用する場合、これらすべてのオブジェクトを注入します。これは2つの理由で悪いようです。

  1. 約3つの依存オブジェクト/クラスがKISSに正常であると聞きました(Keep it Simple Smarty)

  2. オブジェクト/クラスの1つだけが使用されます。したがって、ある意味で、他のものは理由もなくインスタンス化されます。

これらの設計上の考慮事項を解決して、分離されたコードであるが、単純で使用されているコードを満たすにはどうすればよいですか?

4

2 に答える 2

2

あなたがしていることは、実際にいくつかのパラメータをいくつかの機能、いわゆるスクリプトまたはアクションにマッピングすることです。

したがって、最終的には、そのパラメーターまたは名前を関数にマップする方法の規則だけが必要です。関数はどこかにある可能性があるため(他のオブジェクト、グローバルスペース、匿名)、実際には多くのオブジェクトをコントロールクラスに挿入する必要はありませんが、関数とマッピングを挿入する必要があります。

関数名とパラメーター(または「モジュール」と「アクション」)でさらに差別化を加える場合は、コードを大幅に削減し、実際にリクエストに依存関係を注入させることができます。

スクリプトまたはアクション

 Mapping:                  Actions:                  

 "*"                       "_.Exception.Invalid ajax_type"                        
 "signin_control"          "A.SignIn.invoke"
 "signup_control"          "A.SignUp.invoke"  
 "tweet_control"           "A.Tweet.add"      
 "ControlBookmark_add"     "A.Bookmark.add"   
 "ControlBookmark_delete"  "A.Bookmark.delete"
 "ControlTryIt"            "B.ControlTryIt"   
 "ControlSignOut"          "C.SignOut"

 Implementation:

 $action = $map[isset($map[$ajax_type]) ? $ajax_type : '*'];

 Session::start();

 call_user_func_array(
     'call_user_func_array',
     explode('.', $action) + array(NULL, NULL, NULL)
 );

 function _($a, $b) {
     throw new $a($b);
 }

 function A($a, $b) {         
     $maker = new ObjectMaker();
     $maker->$a()->$b();
 }

 function B($a) {
     new $a();
 }

 function C($a) {
    Session::finish();
    B($a);
 }

この擬似コードは、コントロールクラスの実際のビジネスを示しています。入力に基づいていくつかの関数を呼び出します。具体的な依存関係は次のとおりです。

  • ObjectMaker
  • Session
  • $map

セッションは静的であるため、実際に注入できるものに置き換える必要があります。

配列と同様$mapに、注入することもできますが、マッピングのロジックをより内部的なものにする必要がある場合$mapがあるため、がの場合ArrayAccess、これはすでに発生している可能性があります。

非具体的な依存関係は実際の内部に隠されている$ajax_typeため、これらの依存関係は、すでに依存関係になっているマッピングを通じてそのパラメーターに依存しています。したがって、最後の依存関係は次のとおりです。

  • $ajax_type

この依存関係は、コントロールクラスとマッピングの両方に関連しています。したがって、コントロールクラス自体をajaxタイプに依存させることもできます。ただし、静的グローバル関数を使用する場合は、クラス関数内でこれを簡略化して、実際に依存関係を渡すことができるようにします。ファクトリをグローバル関数に入れ、ajaxタイプをiniファイルからロードします。

function ajax_control_factory($inifile)
{
    $maker   = new ObjectMaker();
    $session = new SessionWrap();
    $types   = new AjaxTypesIni($inifile);
    return new AjaxControl($maker, $session, $types);
}

$control = ajax_control_factory($inifile);

printf("Call an nonexistent ajax type: ");
try {
    $control->invokeByType('blurb');
    printf(" - I so failed!\n");
} catch (Exception $e) {
    printf("Exception caught! All good!\n");
}

printf("Add me a bookmark: ");
$control->invokeByType("ControlBookmark_add");
printf("Done! Fine! Superb this works!\n");
printf("Do the two control functions: ");

$control->invokeByType("ControlTryIt");
$control->invokeByType("ControlSignOut");
printf("Done! Fine! Superb this works!\n");

Iniファイル:

*                       = _.Exception.Invalid ajax_type
signin_control          = A.SignIn.invoke
signup_control          = A.SignUp.invoke
tweet_control           = A.Tweet.add
ControlBookmark_add     = A.Bookmark.add
ControlBookmark_delete  = A.Bookmark.delete
ControlTryIt            = B.ControlTryIt
ControlSignOut          = C.SignOut

この作業を行うには、モック用のスタブが必要です。これは、例を使用すると簡単です。

class Mock
{
    public $stub;

    public function __call($name, $args)
    {
        return class_exists($this->stub) ? new $this->stub() : $this->stub;
    }
}

class ObjectMaker extends Mock
{
    public $stub = 'Mock';
}

class ControlTryIt {}
class SignOut {}

class SessionWrap
{
    public function start()
    {
        // session::start();
    }

    public function stop()
    {
        // session::finish();
    }
}

これらは、上記のコードを実行するのに十分です。

Call an nonexistent ajax type: Exception caught! All good!
Add me a bookmark: Done! Fine! Superb this works!
Do the two control functions: Done! Fine! Superb this works!

ajaxタイプ:

class AjaxTypes extends ArrayObject
{
    private $default;
    private $types;

    public function __construct(array $types, $default)
    {
        parent::__construct($types);
        $this->default = $default;
    }

    public function offsetGet($index)
    {
        return parent::offsetExists($index) ? parent::offsetGet($index) : $this->default;
    }
}

class AjaxTypesIni extends AjaxTypes
{
    public function __construct($inifile)
    {
        $map = parse_ini_file($inifile);
        if (!isset($map['*'])) throw new UnexpectedValueException('No * entry found.');
        $default = $map['*'];
        unset($map['*']);
        parent::__construct($map, $default);
    }
}

そして、ajaxコントローラー:

class AjaxControl
{
    private $types;
    private $maker;
    private $session;

    public function __construct(ObjectMaker $maker, SessionWrap $session, AjaxTypes $types)
    {
        $this->types   = $types;
        $this->maker   = $maker;
        $this->session = $session;
    }

    public function invokeByType($type)
    {
        $session = $this->session;
        $maker   = $this->maker;
        $invoke = function($action) use ($session, $maker)
        {
            $_ = function($a, $b)
            {
                throw new $a($b);
            };
            $A = function($a, $b) use ($maker)
            {
                $maker->$a()->$b();
            };

            $B = function ($a)
            {
                new $a();
            };

            $C = function ($a) use ($B, $session)
            {
                $session->stop();
                $B($a);
            };

            $args = explode('.', $action) + array(NULL, NULL, NULL);
            $func = array_shift($args);
            call_user_func_array(${$func}, $args);
        };
        $invoke($this->types[$type]);
        $this->session->start();
    }
}

これは単なる模範です。目的を示すためだけに、これがニーズの設計として適合するという保証はありません。それが示しているのは、実際のコントローラー関数が十分に正規化/モジュール化されていないことです。存在する依存関係をより適切に分析し、それらをハードコーディングする代わりにそれらを注入すると、システムを設計するための最良の方法が自動的に見つかります。

この例でも示されているのは、要求と応答に大量の非表示の依存関係があることです。本当にどこかに線を引き、何をどの方向に通過するかを定義する必要があります。グローバルな静的状態に別れを告げます。常に注入します。役立つ場合は、パラメーターとしてすべてを必要とする関数から始めることもできます。

于 2012-04-18T20:42:38.230 に答える
0

解決済み:

依存性注入をファクトリパターン(オブジェクトメーカー)に配置することで、すべての依存関係を1つの依存関係(オブジェクトメーカー)にまとめることができます。

PHPコントロール

class Control
{
    public static function ajax($ajax_type)
    {
        Session::start();
        switch($ajax_type) 
        {
            case 'signin_control': // uses Message, Text, Database
                $Object = new ObjectMaker();
                $ObjectSignIn=$Object->makeSignIn();
                $ObjectSignIn->invoke();
                break; 
            case 'signup_control':// uses Message, Text, Database
                $Object = new ObjectMaker();
                $ObjectSignUp=$Object->makeSignUp();
                $ObjectSignUp->invoke(); 
                break;
            case 'tweet_control':// uses Message, Text, Database
                $Object = new ObjectMaker();
                $ObjectTweet=$Object->makeTweet();
                $ObjectTweet->add(); 
                break; 
            case 'ControlBookmark_add': // uses Message, Text, Database
                $Object = new ObjectMaker();
                $ObjectBookmark = $Object->makeBookmark();
                $ObjectBookmark->add();
                break; 
            case 'ControlBookmark_delete':// uses Database
                $Object = new ObjectMaker();
                $ObjectBookmark=$Object->makeBookmark();
                $ObjectBookmark->delete(); 
                break; 
            case 'ControlTryIt': // Why Not Session
                new ControlTryIt();
                break; 
            case 'ControlSignOut': 
                Session::finish();
                new ControlSignOut();
                break;
            default:
                throw new Exception('Invalid ajax_type');
        }
    }

ObjecMaker

class ObjectMaker
{
    public function makeSignUp()
    {
        $DatabaseObject = new Database();
        $TextObject = new Text();
        $MessageObject = new Message();

        $SignUpObject = new ControlSignUp();        
        $SignUpObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
        return $SignUpObject;
    }
    public function makeSignIn()
    {
        $DatabaseObject = new Database();
        $TextObject = new Text();
        $MessageObject = new Message();

        $SignInObject = new ControlSignIn();
        $SignInObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
        return $SignInObject;
    }
    public function makeTweet( $DatabaseObject = NULL, $TextObject = NULL, $MessageObject = NULL )
    {
        if( $DatabaseObject == 'small' )
        {
            $DatabaseObject = new Database();
        }
        else if( $DatabaseObject == NULL )
        {
            $DatabaseObject = new Database();
            $TextObject = new Text();
            $MessageObject = new Message();
        }
        $TweetObject = new ControlTweet();        
        $TweetObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
        return $TweetObject;
    }
    public function makeBookmark( $DatabaseObject = NULL, $TextObject = NULL, $MessageObject = NULL )
    {
        if( $DatabaseObject == 'small' )
        {
            $DatabaseObject = new Database();
        }
        else if( $DatabaseObject == NULL )
        {
            $DatabaseObject = new Database();
            $TextObject = new Text();
            $MessageObject = new Message();
        }
        $BookmarkObject = new ControlBookmark();        
        $BookmarkObject->setObjects($DatabaseObject,$TextObject,$MessageObject);
        return $BookmarkObject;
    }
}
于 2012-04-18T17:54:48.593 に答える