Home >Backend Development >PHP Tutorial >The Layer Supertype Pattern: Encapsulating Common Implementation in Multi-Tiered Systems

The Layer Supertype Pattern: Encapsulating Common Implementation in Multi-Tiered Systems

William Shakespeare
William ShakespeareOriginal
2025-02-26 11:51:17375browse

The Layer Supertype Pattern: Encapsulating Common Implementation in Multi-Tiered Systems

Core points

  • Layer supertype mode is crucial in multi-layer systems, and it can encapsulate common implementations in different classes, thereby facilitating code reuse and reducing duplication.
  • Implementing the layer supertype pattern involves creating a shared base class that abstracts public logic and properties and then extends by a more specific subclass.
  • This mode helps maintain a clearer code architecture, as it allows for the modification of shared functionality in one place, thereby enhancing maintainability and scalability.
  • The layer hypertype pattern not only simplifies the code base, but also aligns well with the single responsibility principle because it separates public behavior from class-specific behavior.
  • While this pattern provides many benefits in reducing boilerplate code and redundant code, it must be applied with caution to avoid creating overly complex or large superclass structures that can be difficult to manage.

Inheritance, as one of the cornerstones of object-oriented programming, is like a double-edged sword. It can not only bring powerful code reuse mechanisms, avoid the complexity brought by using combination patterns, but also lead to a chaotic inheritance system. , the behaviors of subtypes and base types are so different that the "IS-A" relationship is in name only. Although there are many pitfalls in inheritance, most of them can be mitigated by rational and moderate use. Code reuse is the root cause of inheritance. Inheritance can play a huge role when adding boilerplate implementations to multi-layer system abstractions. Inheritance provides an easy way to easily generate large numbers of semantically interrelated objects without duplicating code. Its concept is very simple but powerful: first put as much logic as possible within the boundaries of the base type (usually abstract classes, but also concrete classes), and then start deriveing ​​refined subtypes according to more specific needs. This process is usually performed on a "per-layer" basis, thereby providing each layer with its own set of supertypes, whose core functions are refined and extended in turn by the corresponding subtypes. Not surprisingly, this duplicate encapsulation/derived loop follows a design pattern called "layer supertype" (yes, it does have a real academic name, though a bit naive), in the next few lines , I'll dig into how it works internally, and you'll be able to see how easy it is to connect its functionality to the domain model.

Level super type requirements—Defining bloated domain model

It can be said that layer supertypes are the natural and selective evolution of the "common" base type, except that the latter exists within the scope of a specific layer. This plays an important role in multi-layer design where utilizing super-type functions is often a necessary requirement, not just arbitrary decision. In general, the most effective way to understand the practicality behind this pattern is through some practical examples. So, suppose we need to build a simple domain model from scratch, responsible for defining some basic interactions between some blog posts and their corresponding comments. Roughly speaking, the model can be easily outlined as a layer of anemia, containing only a few skeleton classes for modeling articles and comments. The first domain class and its contract may look like this:

<code class="language-php"><?php namespace Model;

interface PostInterface
{
    public function setId($id);
    public function getId();

    public function setTitle($title);
    public function getTitle();

    public function setContent($content);
    public function getContent();

    public function setComment(CommentInterface $comment);
    public function setComments(array $comments);
    public function getComments();
}</code>
<code class="language-php"><?php namespace Model;

class Post implements PostInterface
{
    protected $id;
    protected $title;
    protected $content;
    protected $comments = array();

    public function __construct($title, $content, array $comments = array()) {
        $this->setTitle($title);
        $this->setContent($content);
        if (!empty($comments)) {
           $this->setComments($comments); 
        }
    }

    public function setId($id) {
        if ($this->id !== null) {
            throw new BadMethodCallException(
                "The ID for this post has been set already.");
        }
        if (!is_int($id) || $id             throw new InvalidArgumentException(
                "The post ID is invalid.");
        }
        $this->id = $id;
        return $this;
    }

    public function getId() {
        return $this->id;
    }

    public function setTitle($title) {
        if (!is_string($title) 
            || strlen($title)             || strlen($title) > 100) {
            throw new InvalidArgumentException(
                "The post title is invalid.");
        }
        $this->title = htmlspecialchars(trim($title),
            ENT_QUOTES);
        return $this;
    }

    public function getTitle() {
        return $this->title;
    }

    public function setContent($content) {
        if (!is_string($content) || strlen($content)             throw new InvalidArgumentException(
                "The post content is invalid.");
        }
        $this->content = htmlspecialchars(trim($content),
            ENT_QUOTES);
        return $this;
    }

    public function getContent() {
        return $this->content;
    }

    public function setComment(CommentInterface $comment) {
        $this->comments[] = $comment;
        return $this;
    }

    public function setComments(array $comments) {
        foreach ($comments as $comment) {
            $this->setComment($comment);
        }
        return $this;
    }

    public function getComments() {
        return $this->comments;
    }
}</code>

The driver of the Post class is simple logic, which boils down to defining the data and behavior of some basic post entries. It should be easy to understand. Now let's make the model a little fatter by adding a class to it that generates comments associated with a specific blog entry. Its contract and implementation are as follows:

<code class="language-php"><?php namespace Model;

interface CommentInterface
{
    public function setId($id);
    public function getId();

    public function setContent($content);
    public function getContent();

    public function setAuthor($author);
    public function getAuthor();
}</code>
<code class="language-php"><?php namespace Model;

class Comment implements CommentInterface
{
    protected $id;
    protected $content;
    protected $author;

    public function __construct($content, $author) {
        $this->setContent($content);
        $this->setAuthor($author);
    }

    public function setId($id) {
        if ($this->id !== null) {
            throw new BadMethodCallException(
                "The ID for this comment has been set already.");
        }
        if (!is_int($id) || $id             throw new InvalidArgumentException(
                "The comment ID is invalid.");
        }
        $this->id = $id;
        return $this;
    }

    public function getId() {
        return $this->id;
    }

    public function setContent($content) {
        if (!is_string($content) || strlen($content)             throw new InvalidArgumentException(
                "The content of the comment is invalid.");
        }
        $this->content = htmlspecialchars(trim($content),
            ENT_QUOTES);
        return $this;
    }

    public function getContent() {
        return $this->content;
    }

    public function setAuthor($author) {
        if (!is_string($author) || strlen($author)             throw new InvalidArgumentException(
                "The author is invalid.");
        }
        $this->author = $author;
        return $this;
    }

    public function getAuthor() {
        return $this->author;
    }
}</code>

Like Post, the Comment class is simple. But now with these two classes, we can use the model. For example:

<code class="language-php"><?php use LibraryLoaderAutoloader,   
    ModelPost,
    ModelComment;

require_once __DIR__ . "/Library/Loader/Autoloader.php";
$autoloader = new Autoloader;
$autoloader->register();

$post = new Post(
    "A sample post.",
    "This is the content of the post."
);

$post->setComments(array(
    new Comment(
        "One banal comment for the previous post.",
        "A fictional commenter"),
    new Comment(
        "Yet another banal comment for the previous post.",
        "A fictional commenter")
));

echo $post->getTitle() . " " . $post->getContent() . "<br>";

foreach ($post->getComments() as $comment) {
    echo $comment->getContent() . " " . $comment->getAuthor() .
        "<br>";
}</code>

This is indeed as effective as charm! Using this model is a fairly simple process that requires you to first create some Post objects and then populate them with relevant comments. Yes, life is sweet and beautiful. OK, so far, but it can certainly be better! I'm not trying to destroy the magic of such a wonderful moment, but I have to admit that I feel a slight chill every time I see the implementation of Post and Comment classes. While this is not a serious problem in itself, some methods (such as setId() and setContent()) show typical symptoms of code duplication. Due to some logical problems, solving this problem without carelessness is not as intuitive as it may seem at first glance. First, although they have semantic relationships with each other, each class actually models different types of objects. Second, they implement different interfaces, which means it is difficult to abstract the logic without ending up with a clumsy hierarchy where the "IS-A" condition never holds true. Especially in this case, we can take a more relaxed approach and treat Post and Comment as subtypes of the highly general AbstractEntity supertype. In doing so, placing a shared implementation within the boundaries of an abstract class would be very simple, thus making the definition of subtypes more streamlined. Since the entire abstraction process only takes place at the domain layer, the hypothetical AbstractEntity will be treated as...Yes, you guessed it, a layer supertype. Simple but good, right?

(The remaining code and explanation are omitted here due to space limitations. Note that the code examples in the original text are long, and translating and generalizing all codes will make the answer too verbose. The core idea is to create AbstractEntity Class to extract duplicate code in the Post and Comment classes, thereby reducing code redundancy and improving maintainability. )

Summary

Although inheritance is often considered a mechanism for overestimation and abuse, I hope very few people will disagree now that inheritance is a powerful mechanism that works when used neatly in a multi-layer system prevents duplication of code. Using a simple pattern like layer supertype is an example of the many fascinating advantages that inheritance provides when creating subtypes that share a large number of boilerplate implementations with each other.

(The FAQ part of the original text is also omitted here because its content is a repetition and extension of the core ideas of the article. Translating all the content will make the answer too long. The core ideas have been fully reflected in the above translation.)

The above is the detailed content of The Layer Supertype Pattern: Encapsulating Common Implementation in Multi-Tiered Systems. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn