In Action 实践

The Single Responsibility Principle states that a class should have one, and only one, reason to change. In other words, a class' scope and responsibility should be narrowly focused. As we have said before, ignorance is bliss when it comes to class responsibilities. A class should do its job, and should not be affected by changes to any of its dependencies.

单一职责原则规定一个类有且仅有一个理由使其改变。换句话说,一个类的功能边界和职责应当是十分狭窄且集中的。我们之前就提到过,在类的职责问题上,无知是福。一个类应当做它该做的事儿,并且不应当被它的依赖的任何变化所影响到。

Consider the following class:

考虑下列类:

class OrderProcessor {
    public function __construct(BillerInterface $biller)
    {
        $this->biller = $biller;
    }
    public function process(Order $order)
    {
        $recent = $this->getRecentOrderCount($order);
        if($recent > 0)
        {
            throw new Exception('Duplicate order likely.');
        }

        $this->biller->bill($order->account->id, $order->amount);

        DB::table('orders')->insert(array(
            'account'    =>    $order->account->id,
            'amount'    =>    $order->amount,
            'created_at'=>    Carbon::now()
        ));
    }
    protected function getRecentOrderCount(Order $order)
    {
        $timestamp = Carbon::now()->subMinutes(5);
        return DB::table('orders')->where('account', $order->account->id)
                                                ->where('created_at', '>=', $timestamps)
                                                ->count();
    }
}

What are the responsibilities of the class above? Obviously, its name implies that it is responsible for processing orders. But, based on the getRecentOrderCount method, we can also see that it is responsible for examining an account's order history in the database in order to detect duplicated orders. This extra validation responsibility means that we must change our order processor when our data store changes, as well as when our order validation rules change.

上面这个类的职责是什么?很显然顾名思义,它是用来处理订单的。不过由于 getRecentOrderCount 这个方法的存在,这个类就有了在数据库中审查某帐号订单历史来看有没有重复订单的职责。这个额外的验证职责意味着当我们的存储方式改变或当订单验证规则改变时,我们的这个订单处理器也要跟着改变。

We should extract this responsibility into another class, such as an OrderRepository:

我们必须将这个职责抽离出来放到另外的类里面,比如放到 OrderRepository:

class OrderRepository {
    public function getRecentOrderCount(Account $account)
    {
        $timestamp = Carbon::now()->subMinutes(5);
        return DB::table('orders')->where('account', $account->id)
                                                ->where('created_at', '>=', $timestamp)
                                                ->count();
    }

    public function logOrder(Order $order)
    {
        DB::table('orders')->insert(array(
            'account'    =>    $order->account->id,
            'amount'    =>    $order->amount,
            'created_at'=>    Carbon::now()
        ));
    }
}

Then, we can inject our repository into the OrderProcessor, alleviating it of the responsibility of researching an account's order history:

然后我们可以将我们的资料库(译者注:OrderRepository )注入到 OrderProcessor 里,帮后者承担起对账户订单历史的处理责任:

class OrderProcessor {
    public function __construct(BillerInterface $biller, OrderRepository $orders)
    {
        $this->biller = $biller;
        $this->orders = $orders;
    }

    public function process(Order $order)
    {
        $recent = $this->orders->getRecentOrderCount($order->account);

        if($recent > 0)
        {
            throw new Exception('Duplicate order likely.');
        }

        $this->biller->bill($order->account->id, $order->amount);

        $this->orders->logOrder($order);
    }
}

Now that we have abstracted our order data gathering responsibilities, we no longer have to change our OrderProcessor when the method of retrieving and logging orders changes. Our class responsibilities are more focused and narrow, providing for cleaner, more expressive code, and a more maintainable application.

现在我们提取出了收集订单数据的责任,当读取和写入订单的方式改变时,我们不再需要修改 OrderProcessor 这个类了。我们的类的职责更加的专注和精确,这提供了一个更干净、更有表现力的代码,同时也是更容易维护的代码。

Keep in mind, the Single Responsibility Principle isn't just about less line of code, it's about writing classes that have a narrow responsibility, and a cohesive set of available methods, so make sure that all of the methods in a class are aligned with the overall responsibility of that class. After building a library of small, clear classes with well defined responsibilities, our code will be more decoupled, easier to test, and friendlier to change.

请记住,单一职责原则的关键不仅仅是让函数变短,而是写出职责更精确更高内聚的类,所以要确保类里面所有的方法都属于该类的职责之下的。在建立一个小巧、清晰且职责明确的类库以后,我们的代码会更加解耦,更容易测试,并且更易于更改。

results matching ""

    No results matching ""