使用立面模式管理复杂性

Design patterns are built to standardize solutions for common problems faced in software development. When we develop complex applications, we should allocate sufficient time for planning the design and structure of the app. When we do so, we have the chance to choose appropriate design patterns. But there can be situations where we use a design pattern without even knowing that we’re using one.

设计模式的建立是为了标准化解决软件开发中常见问题的解决方案。 在开发复杂的应用程序时,我们应分配足够的时间来规划应用程序的设计和结构。 当我们这样做时,我们就有机会选择适当的设计模式。 但是在某些情况下,我们甚至不知道正在使用一种设计模式。

Facade is a design pattern used in almost every web application, but often without knowing. The term “design pattern” creates a mental image of something complex and difficult to understand. Even though this can be true sometimes, the Facade pattern is simple to implementation. Let’s see what Facade is and what it does to help us write good code.

外观是一种几乎在每个Web应用程序中使用的设计模式,但是通常是不知道的。 术语“设计模式”创建了一些复杂且难以理解的思想图像。 尽管有时候这是正确的,但是Facade模式易于实现。 让我们看看Facade是什么以及它如何帮助我们编写良好的代码。

借书的过程 (The Process of Borrowing a Book)

Assume that we’re developing an application for a library management system. Borrowing and returning books are obviously the two most important tasks of such systems. But consider a typical implementation of the book borrowing process:

假设我们正在为图书馆管理系统开发一个应用程序。 借书和归还书显然是这种系统最重要的两个任务。 但是考虑一下借书过程的典型实现:

  • A user comes to the library and returns her borrowed books so she can borrow new ones.

    用户来到图书馆并归还借来的书,以便可以借用新书。
  • The user must pay a fine for overdue books.

    用户必须为过期的书支付罚款。
  • The user, or a member of the library staff, searches for a new book.

    用户或图书馆工作人员会搜索一本新书。
  • The availability of the book is verified.

    这本书的可用性得到验证。
  • If the steps above are successfully completed, the location of the book must be retrieved.

    如果上述步骤成功完成,则必须检索该书的位置。
  • The user borrows the book.

    用户借书。
  • The status of the book is marked as unavailable in the system.

    该书的状态在系统中标记为“不可用”。

The implementation of each task is contained in separate classes with their own interfaces. The following code illustrates how a system might let the user borrow a book by calling the necessary methods:

每个任务的实现都包含在具有各自接口的单独类中。 以下代码说明了系统如何通过调用必要的方法让用户借书:

<?php
public class User
{
    public function borrowBook() {
        $bookManager = new Book_Manager();
        $bookManager->returnBooks();

        $bookPayments = new Book_Payments();
        if ($bookPayments->hasOverdueBooks()) {
            $bookPayments->payBookFines();
        }

        $bookLibrary = new Book_Library();
        $bookReservations = new Book_Reservations();

        $book = $bookLibrary->searchBooks();
        $isAvailable = $bookLibrary->isBookAvailable($book);
        $isReserved = $bookReservations->isBookReserved($book); 
        if ($isAvailable && !isReserved) {
            $bookLibrary->locateBook($book);

            $bookManager->borrowBook($book);
            $bookLibrary->updateBookAvailability($book, $status);
        }
    }
}

You can see the process of borrowing a book is actually a complex process! In this implementation, a user has to interact with four different classes and around ten methods to borrow a book.

您可以看到借书的过程实际上是一个复杂的过程! 在此实现中,用户必须与四种不同的类以及大约十种方法进行交互才能借用一本书。

Assume that each bit of functionality is implemented as a separate screen in the application; can you imagine the effort required for borrowing three books with this system? And the borrower doesn’t need to know about functionality such as checking reservations and updating the status. We certainly have a problem with our implementation.

假设功能的每一位都在应用程序中作为单独的屏幕实现; 您能想象使用该系统借三本书需要付出的努力吗? 借款人不需要了解诸如检查预订和更新状态之类的功能。 当然,我们的实施存在问题。

实施图书馆门面 (Implementing a Library Facade)

We need to decouple the user from the complex workflow of the library and allow for a simplified interface exposing just the information directly related to a user – a facade. Let’s see the implementation of the library facade.

我们需要使用户与图书馆的复杂工作流程脱钩,并需要一个简化的界面,以仅显示与用户直接相关的信息(立面)。 让我们看一下库外观的实现。

<?php
class Library_Facade
{
    public function returnBooks() {
        // previous implementation by calling necessary classes
    }

    public function borrowBooks() {
    }

    public function searchBooks() {
    }

    public function reserveBooks() {
    }
}

The user can borrow books by calling the borrowBook() method of the Library_Facade class as shown in the following example:

用户可以通过调用Library_Facade类的borrowBook()方法来Library_Facade ,如以下示例所示:

<?php
class User
{
    public function borrowBook() {
        $libraryFacade = new Library_Facade();
        $libraryFacade->borrowBook();
    }
}

With this facade-based implementation, the user only talks to the Library_Facade class and has no idea how the functionality is implemented beyond it. A user can directly request any feature from the facade and the facade is responsible for handling the complex process and returning the appropriate information. The Facade pattern adheres to the principle of least knowledge in which each unit should have minimal knowledge about the other units.

使用这种基于立面的实现,用户仅与Library_Facade类进行对话,并且不知道如何在其之外实现功能。 用户可以直接从立面请求任何要素,并且立面负责处理复杂的过程并返回适当的信息。 Facade模式遵循最少知识的原则,其中每个单元对其他单元的知识应最少。

Even though the low-level functionality is hidden from the user through the facade, the user can still request low-level classes directly when needed. Think about your own projects and where you might find situations where you’ve implemented the Facade pattern without even realizing it.

即使通过立面对用户隐藏了低级功能,用户仍然可以在需要时直接请求低级类。 考虑一下您自己的项目,以及在哪里可能会发现甚至没有意识到就实现了Facade模式的情况。

外墙图案定义 (Facade Pattern Definition)

Since we’ve identified the process and importance of implementing the Facade pattern, now it’s time to learn the definition of the pattern. The following is extracted from Wikipedia:

既然我们已经确定了实现Facade模式的过程和重要性,那么现在该学习该模式的定义了。 以下摘录自维基百科:

A facade is an object that provides a simplified interface to a larger body of code, such as a class library. A facade can:

外观是为大型代码(例如类库)提供简化接口的对象。 外墙可以:

  • make a software library easier to use, understand, and test since the facade has convenient methods for common tasks;

    由于Facade具有执行常见任务的便捷方法,因此使软件库更易于使用,理解和测试。
  • make the library more readable, for the same reason;

    出于相同的原因,使库更具可读性;
  • reduce dependencies of outside code on the inner workings of a library, since most code uses the facade allowing more flexibility in developing a system;

    减少外部代码对库内部工作的依赖,因为大多数代码使用立面,从而在开发系统时具有更大的灵活性;
  • wrap a poorly designed collection of APIs with a single well-designed API.

    用一个设计良好的API来包装设计不佳的API集合。

Here’s a class diagram of our library example that identifies the components mentioned in the Facade pattern definition.

这是我们的库示例的类图,该类图标识了Facade模式定义中提到的组件。

facade-01

现实世界中的实现 (Real World Implementations)

In the previous sections we learned the theory behind the Facade pattern using a library system as an example. In the real world, facades can be much more complex than the implementation in our library scenario. Let’s review some implementations of the pattern in the context of real-world applications and libraries.

在前面的部分中,我们以图书馆系统为例学习了Facade模式背后的理论。 在现实世界中,立面可能比我们的图书馆方案中的实现复杂得多。 让我们在实际应用程序和库的上下文中回顾该模式的一些实现。

开放式验证的Opauth (Opauth for Open Authentication)

I recently wrote an article about a popular Open Authentication library called Opauth, and I suggest you read it if you haven’t already. Assume we’ve developed a professional social network site and we want our users to be able to use other popular sites such as Twitter, LinkedIn, and Facebook to authenticate. To complete the authentication process we use existing third-party libraries for accessing the networks’ services. Let’s look at some sample code for with a Twitter library for achieving the desired functionality.

最近写了一篇有关流行的开放式身份验证库Opauth的文章,如果您还没有阅读,建议您阅读。 假设我们已经开发了一个专业的社交网站,并且希望我们的用户能够使用其他受欢迎的网站(例如Twitter,LinkedIn和Facebook)进行身份验证。 为了完成身份验证过程,我们使用现有的第三方库来访问网络的服务。 让我们看一下用于实现所需功能的Twitter库的一些示例代码。

<?php
$toauth = new TwitterOAuth('consumer key', 'consumer secret');

$request_token = $toauth->getRequestToken('http://exmaple.com/twitter_oauth.php');

$_SESSION['oauth_token'] = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];

if ($toauth->http_code == 200) {
    $url = $toauth->getAuthorizeURL($request_token['oauth_token']);
    header('Location: '. $url);
}
else {
    // Generate error
}

As you can see, we call a set of Twitter-specific library methods to implement the desired functionality. A similar approach would be necessary for both LinkedIn and Facebook. The process has already become complex. We’re not developing a Twitter, Facebook, or Linkedin application; we should just validate the credentials and authenticate the user. Our application shouldn’t be worried about the implementation of each of these services.

如您所见,我们调用一组特定于Twitter的库方法来实现所需的功能。 LinkedIn和Facebook都必须采用类似的方法。 这个过程已经变得很复杂。 我们不开发Twitter,Facebook或Linkedin应用程序; 我们应该只验证凭据并验证用户身份。 我们的应用程序不必担心这些服务的实现。

We can solve this problem by using the Opauth library as a facade interface. First we need to specify the login URLs of the desired services in a common format to be identified by the Opauth plugin. Consider the following code for implementing the authentication process.

我们可以通过使用Opauth库作为Facade接口来解决此问题。 首先,我们需要以通用格式指定所需服务的登录URL,以由Opauth插件标识。 考虑以下代码以实现身份验证过程。

<?php
public function login($stratergy = '') {
    if ($stratergy != '') {
        $this->opauth_lib->initialize();
    }
}

Once the login link is requested, Opauth identifies the requested service from the URL and initializes the library to redirect the user for authentication. Our application now only needs to create the login links and call the initialize method. All of the complex authentication stuff is handled behind-the-scenes using the respective libraries for each service. This can be considered a perfect example for effectively using the Facade pattern.

请求登录链接后,Opauth会从URL识别请求的服务,并初始化库以重定向用户以进行身份​​验证。 现在,我们的应用程序仅需要创建登录链接并调用initialize方法。 使用每个服务的相应库,所有复杂的身份验证内容都在后台进行处理。 这可以被视为有效使用Facade模式的完美示例。

WordPress元功能 (WordPress Meta Functions)

WordPress is not one of the most popular frameworks among serious PHP developers considering the quality of its code. But we can easily find a number of successful facade implementations inside the WordPress codebase. Here I’ll take a look at the update_post_meta() function for saving custom data for WordPress posts.

考虑到其代码的质量,WordPress在认真PHP开发人员中并不是最受欢迎的框架之一。 但是我们可以轻松地在WordPress代码库中找到许多成功的外观实现。 在这里,我将介绍用于保存WordPress帖子的自定义数据的update_post_meta()函数。

WordPress allows us to create custom fields associated with existing posts. Think of how we save these fields in a usual situation… we have to implement all the following tasks:

WordPress允许我们创建与现有帖子关联的自定义字段。 考虑一下在通常情况下如何保存这些字段……我们必须执行以下所有任务:

  • Validate the field data

    验证现场数据
  • Filter the data for HTML tags, scripts, and SQL injections

    筛选HTML标记,脚本和SQL注入的数据
  • Check the existence of the field in database

    检查数据库中字段的存在
  • Save or update the record based on the existence status

    根据存在状态保存或更新记录

That’s quite a lot of work to save one single custom field! WordPress hides the complexity of saving these fields by providing a built-in function called update_post_meta() to act as a facade. This permits us to focus on passing the necessary data related to our application; all of the aforementioned tasks are hidden from the user.

保存一个自定义字段需要大量的工作! WordPress通过提供一个称为update_post_meta()的内置函数充当外观,隐藏了保存这些字段的复杂性。 这使我们可以专注于传递与我们的应用程序相关的必要数据; 所有上述任务对用户都是隐藏的。

Now consider the implementation of update_post_meta() to identify its functionality as a facade:

现在考虑执行update_post_meta()以将其功能标识为外观:

<?php
function update_post_meta($post_id, $meta_key, $meta_value, $prev_value = '') {
    // make sure meta is added to the post, not a revision
    if ($the_post = wp_is_post_revision($post_id))
        $post_id = $the_post;

    return update_metadata('post', $post_id, $meta_key, $meta_value, $prev_value);
}

function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
    // expected_slashed ($meta_key)
    $meta_key = stripslashes($meta_key);
    $passed_value = $meta_value;
    $meta_value = stripslashes_deep($meta_value);
    $meta_value = sanitize_meta($meta_key, $meta_value, $meta_type);

    $check = apply_filters("update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value);
    if (null !== $check)
        return (bool) $check;

    // Compare existing value to new value if no prev value given and the key exists only once.
    if (empty($prev_value)) {
        $old_value = get_metadata($meta_type, $object_id, $meta_key);
        if (count($old_value) == 1) {
            if ($old_value[0] === $meta_value)
                return false;
        }
    }

    $wpdb->update($table, $data, $where);
}

Only the necessary code is shown; the complete source code for the update_metadata() function is available in meta.php file inside the wp-includes directory. But you can see all of the validation, filtering, and database updates are implemented here and only the facade interface has knowledge about the details.

仅显示必要的代码; wp-includes目录中的meta.php文件中提供了update_metadata()函数的完整源代码。 但是您可以在此处看到所有验证,过滤和数据库更新均已实现,并且只有Facade界面具有有关细节的知识。

结论 (Conclusion)

Facade is one of the most simple and easy to use design patterns in software development. Throughout this article I talked about various implementations of the Facade pattern. Now it’s time to share your experiences in the comments below. Do you know of any library or service that makes use of facades? Feel free to share the practical implementations of the Facade pattern you’ve come across.

Facade是软件开发中最简单易用的设计模式之一。 在本文中,我讨论了Facade模式的各种实现。 现在是时候在下面的评论中分享您的经验了。 您知道利用立面的任何图书馆或服务吗? 随时分享您遇到的Facade模式的实际实现。

Image via Fotolia

图片来自Fotolia

翻译自: https://www.sitepoint.com/manage-complexity-with-the-facade-pattern/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值