虚拟机 全局代理 主机代理

tech2023-12-02  36

虚拟机 全局代理 主机代理

Standing behind a rather fancy and flowery name, Virtual Proxies are quite possibly one of the most visible examples of why the “Programming to Interfaces” mantra is a lot more than just a dull dogmatic principle. Resting on the foundation of Polymorphism (dynamic Polymorphism, not the ad-hoc one often achieved through plain method overriding), Virtual Proxies are a simple yet solid concept which allows you to defer the construction/loading of expensive object graphs without having to modify client code.

Virtual Proxies背后有一个花哨和花哨的名字,很可能是为什么“编程到接口”口头禅不仅仅是一个呆板的教条原则的最明显的例子之一。 虚拟代理基于多态(动态多态,而不是通常通过简单方法重写实现的即席即用)的基础,是一个简单而可靠的概念,可让您推迟构造/加载昂贵的对象图而不必修改客户端码。

One of the great things about proxies is that they can be conceptually designed to work with either single objects or with collections of them (or with both, even though doing so can jeopardize separation of concerns and become difficult to manage over time). To demonstrate from a hands-on perspective how to exploit the functionality made available by Virtual Proxies, in the first instalment of this series I went through the development of a few examples, showing how to use a basic proxy for pulling in an aggregate from the database in order to fulfill a simplistic domain model.

代理的一大优点是,它们在概念上可以设计为与单个对象或它们的集合一起使用(或与它们同时使用,即使这样做可能会危害关注点的分离并随着时间的推移变得难以管理)。 为了从亲身实践的角度演示如何利用Virtual Proxies提供的功能,在本系列的第一部分中,我完成了一些示例的开发,展示了如何使用基本代理从数据库中提取聚合。数据库以实现简化的域模型。

Even though experience was hopefully didactic, and with luck also fun, its flip-side was somewhat deceiving, as it showed the nuts and bolts of Virtual Proxies but not how to implement them in a more realistic scenario. Proxies are a hard-to-beat armada when it comes to lazy-loading collections of domain objects from storage. To get an idea of the concept just think about a batch of blog posts where each set of related comments can be fetched on demand from the database; surely you’ll grasp why proxies can deliver superbly well what they promise in cases like this.

尽管经验是有希望的,而且运气也很有趣,但它的另一面却具有欺骗性,因为它显示了虚拟代理的基本要素,而不是如何在更现实的场景中实现它们。 当从存储中延迟加载域对象的集合时,代理是难以抗拒的舰队。 要了解这个概念,只需考虑一批博客文章,可以根据需要从数据库中获取每组相关的评论。 当然,您将了解为什么代理可以很好地交付他们在此类情况下的承诺。

As usual, practice is the best teacher. In this part I’ll showcase how to hook up a proxy to a specific collection of domain objects. I’ll be recreating at a very basic level this typical scenario, that way you can see its driving logic in a pretty painless fashion.

和往常一样,实践是最好的老师。 在这一部分中,我将展示如何将代理连接到特定的域对象集合。 我将在一个非常基本的水平上重新创建这种典型场景,以这种方式您可以非常轻松地看到其驱动逻辑。

创建域对象的集合 (Creating a Collection of Domain Objects)

As I explained, Virtual Proxies are commonly brought to life when it comes to fetching aggregate roots from the persistence layer which are bound to a collection of underlying domain objects. Because of their inherently prolific nature, collections are, in many cases, expensive to setup up front, something that makes them good candidates for being dragged in on request to overhead caused by expensive trips to the database.

正如我所解释的,当从持久层获取聚合根时,通常会使用虚拟代理,这些根绑定到底层域对象的集合。 由于其固有的多产性质,在许多情况下,集合的建立起来很昂贵,这使它们成为应要求而被拖入数据库的昂贵行程所造成的开销的良好候选者。

Moreover, considering the “one-to-many” association between blog posts and the corresponding comments reflects fairly faithfully in this use case, it’d be pretty instructive to first model the relationship through some straightforward domain classes before working on a concrete proxy.

此外,考虑到博客帖子和相应评论之间的“一对多”关联在此用例中相当真实地反映出来,在进行具体代理之前,首先通过一些简单的域类对关系进行建模将非常有启发性。

To keep things easy to understand, the first two players I’ll be adding to the testing stage will be a segregated interface, along with a basic implementer. Joining forces, these two will define the contract and implementation of generic blog post objects:

为了使事情易于理解,我将在测试阶段添加的前两个参与者将是一个隔离的接口,以及一个基本的实现程序。 这两个因素将共同定义通用博客文章对象的合同和实现:

<?php namespace Model; use ModelCollectionCommentCollectionInterface; 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 setComments(CommentCollectionInterface $comments); public function getComments(); } <?php namespace Model; use ModelCollectionCommentCollectionInterface; class Post implements PostInterface { protected $id; protected $title; protected $content; protected $comments; public function __construct($title, $content, CommentCollectionInterface $comments = null) { $this->setTitle($title); $this->setContent($content); $this->comments = $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 < 1) { 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) < 2 || 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) < 2) { 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 setComments(CommentCollectionInterface $comments) { $this->comments = $comments; return $this; } public function getComments() { return $this->comments; } }

Understanding the logic behind the above Post class is a trivial process that doesn’t need really require an explanation. Still, there’s a relevant detail worth noting here: the class explicitly declares in the constructor a dependency to a still undefined collection of comments. Let’s create now the class that spawns post comments:

了解上述Post类背后的逻辑是一个微不足道的过程,实际上并不需要进行解释。 仍然有一个相关的细节在这里值得注意:类在构造函数中显式声明了对仍未定义的注释集合的依赖。 现在让我们创建产生评论的类:

<?php namespace Model; interface CommentInterface { public function setId($id); public function getId(); public function setContent($content); public function getContent(); public function setPoster($poster); public function getPoster(); } <?php namespace Model; class Comment implements CommentInterface { protected $id; protected $content; protected $poster; public function __construct($content, $poster) { $this->setContent($content); $this->setPoster($poster); } 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 < 1) { 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) < 2) { 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 setPoster($poster) { if (!is_string($poster) || strlen($poster) < 2 || strlen($poster) > 30) { throw new InvalidArgumentException( "The poster is invalid."); } $this->poster = htmlspecialchars(trim($poster), ENT_QUOTES); return $this; } public function getPoster() { return $this->poster; } }

So far, things are rolling along smoothly. There’s not much that can be said about the above domain classes except that they’re slim blocks of a basic Domain Model, where each blog post object exposes a “one-to-many” association with the related comments. Feel free to call me a purist if you want, but in my view the model’s current implementation looks half-baked and clunky if it doesn’t get spiced up with a collection of comments. Let’s make the model a bit richer by adding to it the logic of this extra component:

到目前为止,事情进展顺利。 关于上述领域类,除了它们是基本领域模型的苗条块外,没有什么可说的了,在每个领域中 ,每个博客帖子对象都公开了与相关注释“一对多”的关联。 如果愿意,可以随意称呼我为纯粹主义者,但是在我看来,如果模型的当前实现没有引起过多评论,那么它看起来就显得有些笨拙和笨拙。 通过添加此额外组件的逻辑,使模型更加丰富:

<?php namespace ModelCollection; interface CommentCollectionInterface extends Countable, IteratorAggregate { public function getComments(); } <?php namespace ModelCollection; use ModelCommentInterface; class CommentCollection implements CommentCollectionInterface { protected $comments = array(); public function __construct(array $comments = array()) { if ($comments) { foreach($comments as $comment) { $this->addComment($comment); } } } public function addComment(CommentInterface $comment) { $this->comments[] = $comment; return $this; } public function getComments() { return $this->comments; } public function count() { return count($this->comments); } public function getIterator() { return new ArrayIterator($this->comments); } }

If you’re observant and scan through the CommentCollection class, the first thing you’ll spot is the fact that it’s nothing but an iterable, countable array wrapper hidden behind a fancy disguise. In fact, array collections come in different forms and flavors, but most of the times they’re just plain usages of the Iterator and ArrayAccess SPL classes. In this case, I wanted to save myself (and you) from tackling such a boring task and made the class an implementer of IteratorAggregate.

如果您观察并浏览CommentCollection类,那么您会发现的第一件事是,它只是隐藏在奇特的伪装背后的可迭代的,可数的数组包装器。 实际上,数组集合有不同的形式和风格,但是大多数情况下,它们只是Iterator和ArrayAccess SPL类的简单用法。 在这种情况下,我想让自己(和您)免于处理如此无聊的任务,并使该类成为IteratorAggregate的实现者。

With the comment collection already in place, we could just go one step further and put the domain model to do what it’s supposed to do – massage a few blog post objects here and there, and even interconnect them with a batch of comments fetched eagerly from the database. But in doing so we’d just be cheating ourselves and not exploiting the functionality that Virtual Proxies offer to its fullest extent.

有了注释集合之后,我们可以再走一步,将域模型用于应做的事情–在各处按摩一些博客文章对象,甚至将它们与从中急​​切获取的一批注释进行互连。数据库。 但是这样做的话,我们只是在欺骗自己,而没有充分利用Virtual Proxies提供的功能。

Considering that in a typical implementation proxies expose the same API that the actual domain objects do, a proxy that interacts with the previous CommentCollection class should implement the CommentCollectionInterface as well to honor the contract with client code without dropping in somewhere a bunch of smelly conditionals.

考虑到在典型的实现中,代理公开了与实际域对象相同的API,因此与以前的CommentCollection类进行交互的代理也应实现CommentCollectionInterface ,以遵守与客户端代码的约定,而不会丢掉一堆臭的条件。

通过虚拟代理与域对象集合接口 (Interfacing to Collections of Domain Objects via a Virtual Proxy)

To be frank, array-wrapping collections like the one earlier can exist happily on their own without having to rely on any other dependencies. (If you’re skeptical, feel free to check how collections in Doctrine do their stuff behind the scenes.) Despite this, remember that I’m trying to implement a proxy that mimics the behavior of a real collection of post comments, but that is in fact a lightweight stand-in.

坦率地说,像以前那样的数组包装集合可以快乐地独立存在,而不必依赖任何其他依赖项。 (如果您对此表示怀疑,请随时检查Doctrine中的集合如何在后台进行操作。)尽管如此,请记住,我正在尝试实现一个模仿真实评论集合的行为的代理,但是实际上是轻量级的替代品。

The question that begs asking is: how can the comments be pulled from the database and dropped into the earlier collection? There’s a few ways to accomplish this, but one that I find most appealing is through a data mapper since it promotes persistence agnosticism.

可能要问的问题是:如何从数据库中提取注释并将其放入早期集合中? 有几种方法可以完成此操作,但是我发现最吸引人的一种方法是通过数据映射器,因为它可以促进持久性不可知论。

The mapper below does a decent job of fetching collections of post comments from storage. Check it out:

下面的映射器在从存储中获取帖子评论的集合方面做得不错。 看看这个:

<?php namespace ModelMapper; interface CommentMapperInterface { public function fetchById($id); public function fetchAll(array $conditions = array()); } <?php namespace ModelMapper; use LibraryDatabaseDatabaseAdapterInterface, ModelCollectionCommentCollection, ModelComment; class CommentMapper implements CommentMapperInterface { protected $adapter; protected $entityTable = "comments"; public function __construct(DatabaseAdapterInterface $adapter) { $this->adapter = $adapter; } public function fetchById($id) { $this->adapter->select($this->entityTable, array("id" => $id)); if (!$row = $this->adapter->fetch()) { return null; } return $this->createComment($row); } public function fetchAll(array $conditions = array()) { $collection = new CommentCollection; $this->adapter->select($this->entityTable, $conditions); $rows = $this->adapter->fetchAll(); if ($rows) { foreach ($rows as $row) { $collection->addComment($this->createComment($row)); } } return $collection; } protected function createComment(array $row) { return new Comment($row["content"], $row["poster"]); } }

While the finders exposed by the CommentMapper class in general stick to the API that one might expect in a standard data mapper implementation, by far the fetchAll() method is the flashiest kid on the block. It first pulls in all of the blog post comments from storage and drops them into the collection, which is finally returned to client code. If you’re like me, an alarm bell might be going off in your head because the collection is directly instantiated inside the method.

虽然CommentMapper类公开的CommentMapper通常使用标准数据映射器实现中可能期望的API,但到目前为止, fetchAll()方法是该块上最炫的孩子。 它首先从存储中提取所有博客文章评论,然后将其放入集合中,最后返回给客户端代码。 如果您像我一样,可能会因为您直接在方法内部实例化集合而在您的脑海中发出警报。

In fact, there’s no need to be frantic about new operators living shyly outside factories, at least in this case, as the collection is actually a generic structure that falls under an “newable” category rather than under an “injectable” one. Regardless, if you feel a little bit less guilty by injecting the collection in the mapper’s constructor, feel free to do so.

实际上,至少在这种情况下,不必担心new操作员会在工厂外害羞地生活,因为该收藏实际上是一种通用结构,属于“新”类别而不是“可注射”类别。 无论如何,如果您通过将集合注入到映射器的构造函数中而感到内less,请随意这样做。

With the comment mapper in place, it’s time to go through the true epiphany moment and build the proxy class that mediates with the earlier collection:

有了注释映射器,就该经历真正的顿悟时刻,并构建与早期集合进行中介的代理类:

<?php namespace ModelProxy; use ModelCollectionCommentCollectionInterface, ModelMapperCommentMapperInterface; class CommentCollectionProxy implements CommentCollectionInterface { protected $comments; protected $postId; protected $commentMapper; public function __construct($postId, CommentMapperInterface $commentMapper) { $this->postId = $postId; $this->commentMapper = $commentMapper; } public function getComments() { if ($this->comments === null) { if(!$this->comments = $this->commentMapper->fetchAll( array("post_id" => $this->postId))) { throw new UnexpectedValueException( "Unable to fetch the comments."); } } return $this->comments; } public function count() { return count($this->getComments()); } public function getIterator() { return $this->getComments(); } }

As you might expect, CommentCollectionProxy implements the same interface than one of the real comment collections. However, its getComments() method does the real leg work behind the scenes and lazy-loads the comments from the database through the mapper passed in the constructor.

如您所料, CommentCollectionProxy实现的界面与实际的评论集合之一相同。 但是,它的getComments()方法在幕后起作用,并通过构造函数中传递的映射器从数据库延迟加载注释。

This simple yet effective trick allows you to do all sort of clever things with the comments, without suffering from excessive underarm sweating. Do you want to see what ones? Well, let’s say you need to fetch all the comments bound to a specific blog post from the database. The following snippet gets the job done:

这个简单而有效的技巧使您可以对注释进行各种巧妙的处理,而不会因腋下出汗过多而受苦。 你想看什么吗? 好吧,假设您需要从数据库中获取绑定到特定博客文章的所有评论。 以下代码段可完成工作:

<?php use LibraryLoaderAutoloader, LibraryDatabasePdoAdapter, ModelMapperCommentMapper, ModelProxyCommentCollectionProxy, ModelComment, ModelPost; require_once __DIR__ . "/Library/Loader/Autoloader.php"; $autoloader = new Autoloader; $autoloader->register(); $adapter = new PdoAdapter("mysql:dbname=blog", "myfancyusername", "mysecretpassword"); $commentMapper = new CommentMapper($adapter); $comments = $commentMapper->fetchAll(array("post_id" => 1)); $post = new Post("The post title", "This is just a sample post.", $comments); echo $post->getTitle() . " " . $post->getContent() . "<br />"; foreach ($post->getComments() as $comment) { echo $comment->getContent() . " " . $comment->getPoster() . "<br />"; }

The downside of this approach is that the comments are first pulled in from storage and then injected into the internals of the post object. How about doing the inverse, but this time by “fooling” client code with the proxy?

这种方法的缺点是首先将注释从存储中拉出,然后注入到post对象的内部。 如何进行反向操作,但是这次是通过使用代理“欺骗”客户端代码来完成的?

<?php $comments = new CommentCollectionProxy(1, new CommentMapper($adapter)); $post = new Post("The post title", "This is just a sample post.", $comments); echo $post->getTitle() . " " . $post->getContent() . "<br />"; foreach ($post->getComments() as $comment) { echo $comment->getContent() . " " . $comment->getPoster() . "<br />"; }

Not only is the set of comments lazy-loaded transparently from the database after the proxy was dropped into the foreach loop, but the API exposed to the client code keeps its pristine structure untouched the whole time. Do we even dare ask for anything better? Unless you’re insanely greedy, I hardly think so.

在将代理放入foreach循环后,不仅从数据库透明地懒惰地加载了注释集,而且公开给客户端代码的API始终保持其原始结构不变。 我们甚至不敢要求更好的东西吗? 除非你疯狂地贪婪,否则我几乎不会这样认为。

In either case, at this point you should be aware of what’s actually going on under the hood of Virtual Proxies and how to make the most of the functionality when it comes to improving the efficiency of the operations traded between domain objects and the underlying persistence layer.

无论哪种情况,在这一点上,您都应该了解虚拟代理背后的实际情况,以及在提高域对象与基础持久层之间交易的效率时如何充分利用功能。

总结思想 (Closing Thoughts)

Although trivial, specially if you’re bold enough to use it in production, the earlier example shows in a nutshell a few interesting concepts. First, Virtual Proxies are not only a snap to set up and use, but they’re hard to beat when it comes to mixing up different implementations at runtime in order to defer the execution of expensive tasks, such as lazy-loading large chunks of data from the storage layer, or creating heavyweight object graphs.

尽管微不足道,但特别是如果您有足够大胆的能力在生产中使用它,则前面的示例简要概述了一些有趣的概念。 首先,虚拟代理不仅易于设置和使用,而且在运行时混合不同的实现以延迟执行昂贵的任务(例如延迟加载较大的任务)时,也很难击败虚拟代理。来自存储层的数据,或创建重量级的对象图。

Second, they’re a classic example on how the use of Polymorphism can be an effective vaccine for reducing common Rigidity and Fragility issues that many object-oriented applications suffer from. Furthermore, as PHP is both easy in its object model and supporting Closures, it’s possible to cook up a nice mixture of these features and build proxies whose underlying logic is driven by the goodies of closures. If you want to tackle this challenge on your own, then you have my blessings in advance.

其次,它们是一个经典的例子,说明了如何将多态性用作减少许多面向对象应用程序遭受的常见刚性和脆弱性问题的有效疫苗。 此外,由于PHP在其对象模型和支持Closures方面都很容易,因此有可能精心组合这些功能并构建代理,这些代理的基本逻辑是由Closure的优点驱动的。 如果您想独自应对这一挑战,那么请先取得我的祝福。

Image via imredesiuk / Shutterstock

图片来自imredesiuk / Shutterstock

翻译自: https://www.sitepoint.com/intro-to-virtual-proxies-2/

虚拟机 全局代理 主机代理

相关资源:jdk-8u281-windows-x64.exe
最新回复(0)