官术网_书友最值得收藏!

Single responsibility principle

The single responsibility principle deals with classes that try to do too much. The responsibility in this context refers to reason to change. As per the Robert C. Martin definition:

"A class should have only one reason to change."

The following is an example of a class that violates the SRP:

class Ticket {
    const SEVERITY_LOW = 'low';
    const SEVERITY_HIGH = 'high';
    // ...
    protected $title;
    protected $severity;
    protected $status;
    protected $conn;

    public function __construct(\PDO $conn) {
        $this->conn = $conn;
    }

    public function setTitle($title) {
        $this->title = $title;
    }

    public function setSeverity($severity) {
        $this->severity = $severity;
    }

    public function setStatus($status) {
        $this->status = $status;
    }

    private function validate() {
        // Implementation...
    }

    public function save() {
        if ($this->validate()) {
            // Implementation...
        }
    }

}

// Client
$conn = new PDO(/* ... */);
$ticket = new Ticket($conn);
$ticket->setTitle('Checkout not working!');
$ticket->setStatus(Ticket::STATUS_OPEN);
$ticket->setSeverity(Ticket::SEVERITY_HIGH);
$ticket->save();

The Ticket class deals with validation and saving of the ticket entity to the database. These two responsibilities are its two reasons to change. Whenever the requirements change regarding the ticket validation, or regarding the saving of the ticket, the Ticket class will have to be modified. To address the SRP violation here, we can use the assisting classes and interfaces to split the responsibilities.

The following is an example of refactored implementation, which complies with SRP:

interface KeyValuePersistentMembers {
    public function toArray();
}

class Ticket implements KeyValuePersistentMembers {
    const STATUS_OPEN = 'open';
    const SEVERITY_HIGH = 'high';
    //...
    protected $title;
    protected $severity;
    protected $status;

    public function setTitle($title) {
        $this->title = $title;
    }

    public function setSeverity($severity) {
        $this->severity = $severity;
    }

    public function setStatus($status) {
        $this->status = $status;
    }

    public function toArray() {
        // Implementation...
    }
}

class EntityManager {
    protected $conn;

    public function __construct(\PDO $conn) {
        $this->conn = $conn;
    }

    public function save(KeyValuePersistentMembers $entity)
    {
        // Implementation...
    }
}

class Validator {
    public function validate(KeyValuePersistentMembers $entity) {
        // Implementation...
    }
}

// Client
$conn = new PDO(/* ... */);

$ticket = new Ticket();
$ticket->setTitle('Payment not working!');
$ticket->setStatus(Ticket::STATUS_OPEN);
$ticket->setSeverity(Ticket::SEVERITY_HIGH);

$validator = new Validator();

if ($validator->validate($ticket)) {
    $entityManager = new EntityManager($conn);
    $entityManager->save($ticket);
}

Here we introduced a simple KeyValuePersistentMembers interface with a single toArray method, which is then used with both EntityManager and Validator classes, both of which take on a single responsibility now. The Ticket class became a simple data holding model, whereas client now controls instantiation, validation, and save as three different steps. While this is certainly no universal formula of how to separate responsibilities, it does provide a simple and clear example of how to approach it.

Designing with the single responsibilities principle in mind yields smaller classes with greater readability and easier to test code.

主站蜘蛛池模板: 宕昌县| 西贡区| 故城县| 牙克石市| 江津市| 木里| 肇东市| 永寿县| 凤城市| 建阳市| 澄城县| 林芝县| 宁强县| 镇安县| 女性| 黑龙江省| 枝江市| 宣恩县| 沂水县| 绩溪县| 宜都市| 西乌珠穆沁旗| 叙永县| 鄄城县| 巢湖市| 东宁县| 南投市| 通城县| 冕宁县| 盱眙县| 泸西县| 蛟河市| 桓仁| 高密市| 莎车县| 江门市| 开原市| 崇仁县| 洱源县| 玛多县| 芦溪县|