猿问

访问者模式在 API 中有什么好处?

我试图了解在 API 中使用访问者模式的好处。下面的例子是我看到的一个例子,我想要一个例子来说明为什么这种模式是有益的,即好处。什么是负面的替代实现以及与此相比的原因。从下面的实现中可以获得什么好处。在这个 api 中,它联系多所大学以获取他们提供的课程。然后,每个获取课程服务使用访问者模式具有定义数量的响应:


控制器


[HttpGet]

public async Task<IActionResult> Get()

{

    // CourseService already retrieved for a given uni 

    var result = await courseService.GetCourses(userSession);

    return result.Accept(new CourseVisitor());

}

服务 - 每个 Uni 都有自己的 GetCourses 服务,但由于访客模式,它们都设置了响应


public async Task<CoursesResult> GetCourses(UserSession userSession) {


// Depending on response from a given uni a set number of responses can be returned across ass uni services e.g

return new CoursesResult.BadRequest(); **or**

return new CoursesResult.Success(); etc

}

元素抽象/具体元素


  public abstract class GetCourses

    {

        public abstract T Accept<T>(ICourseVisitor<T> visitor);


        public class Successful : CoursesResult

        {

            public CourseList Response { get; }


            public Successful(CourseList response)

            {

                Response = response;

            }


            public override T Accept<T>(ICourseVisitor<T> visitor)

            {

                return visitor.Visit(this);

            }

        }

   // Other responses then defined e.g Bad Request

访问者


    public interface ICourseVisitor<out T>

{

    T Visit(GetCoursesResult.Successful result);

    T Visit(GetCoursesResult.BadRequest result);

游客


    internal class CourseVisitor : ICourseVisitor<IActionResult>

{

    public IActionResult Visit(GetCourses.Successful result)

    {

        return new OkObjectResult(result.Response);

    }

更新的查询 此外,我试图了解为什么服务无法返回如下内容:


//Service returns this: return new Successful(listResponse)


 public interface ICoursesResult

    {

      IActionResult Accept();

    }


 public class Successful : ICoursesResult

    {

        public CourseList Response { get; }


        public Successful(CourseList response)

        {

            Response = response;

        }


        public IActionResult Accept()

        {

            return OkObjectResult(Response);

        }

    }


qq_遁去的一_1
浏览 120回答 2
2回答

MMTTMM

在代码项目中对此进行了广泛的研究 -访客模式重新解释。我将提供标题。访问者模式是为了解决问题,通过呈现两个方面:有一个迭代机制,它知道如何迭代对象hirerachy。它对层次结构中对象的行为一无所知。需要实现的新行为对迭代机制一无所知,它们不知道如何迭代对象层次结构。现在这两个方面,是相互独立的,不应该相互混淆。所以,这一切都是关于称为单一责任主体的 OOP 主体,带您回到SOLID 架构。此功能的主要参与者是:访问者- 定义访问操作的接口。这是访问者模式的核心。它为对象结构中的每种类型的 Concreate Element 定义了一个访问操作。ConcreateVisitor&nbsp;- 实现在访问者接口中定义的操作。ElementBase:它是一个抽象/接口,它定义了以访问者为参数的 Accept 操作。ConcreateElement&nbsp;- 这些类型实现了 Element 接口的 Accept 方法。对象结构——它将数据结构的所有元素保存为集合、列表或访问者可以枚举和使用的东西。它为所有访问者提供访问其元素的界面。这些元素包括称为“接受”的方法。然后枚举集合现在,所有这些模式的目标,关键是创建功能有限的数据模型和一组具有特定功能的访问者,这些访问者将对数据进行操作。该模式允许访问者访问数据结构的每个元素,并将对象作为参数传递给访问者方法。毕竟的好处-将算法与其数据模型分离的关键是能够轻松添加新行为。数据模型的类是使用名为 Visit 的公共方法创建的,该方法可以在运行时接受访问者对象。然后可以创建不同的访问者对象并将其传递给此方法,然后此方法对访问者方法有一个回调,将自身作为参数传递给它。另一件值得一提的是:向对象层次结构添加新类型需要更改所有访问者,这应该被视为一个优势,因为它肯定会迫使我们将新类型添加到您保留某些特定于类型代码的所有位置。基本上它不只是让你忘记这一点。访问者模式仅有用:如果您要实现的接口是相当静态的并且不会发生太大变化。如果预先知道所有类型,即在设计时必须知道所有对象。在底线:访客实现以下设计原则:关注点分离 - 访问者模式促进了这一原则,将多个方面/关注点分离到多个其他类,因为它鼓励更简洁的代码和代码可重用性,并且代码更易于测试。单一职责原则 - 访问者模式也强制执行此原则。一个对象应该有几乎一个责任。不相关的行为必须从它分离到另一个类。开闭原则——访问者模式也遵循这个原则,就好像,我们要扩展一个对象的行为一样,原来的源代码是没有改变的。访问者模式为我们提供了将其分离到另一个类并在运行时将这些操作应用于对象的机制。访客实施的好处是:将数据结构的行为与它们分开。创建单独的访问者对象以实现此类行为。它解决了很少面临但具有重要影响的双重调度问题。您可以深入研究这篇文章以了解其全部含义,但如果我要举一个例子:首先,我们将定义我们称为 IVisitable 的接口。它将定义一个接受 IVisitor 参数的 Accept 方法。该接口将作为产品列表中所有类型的基础。所有类型,如 Book、Car 和 Wine(在我们的示例中)都将实现此类型。/// <summary>/// Define Visitable Interface.This is to enforce Visit method for all items in product./// </summary>internal interface IVisitable{&nbsp; &nbsp; void Accept(IVisitor visit);}&nbsp; &nbsp;然后我们将实现它:&nbsp; #region "Structure Implementations"&nbsp; &nbsp; /// <summary>&nbsp; &nbsp; /// Define base class for all items in products to share some common state or behaviors.&nbsp; &nbsp; /// Thic class implement IVisitable,so it allows products to be Visitable.&nbsp; &nbsp; /// </summary>&nbsp; &nbsp; internal abstract class Product : IVisitable&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public int Price { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; public abstract void Accept(IVisitor visit);&nbsp; &nbsp; }&nbsp; &nbsp; /// <summary>&nbsp; &nbsp; /// Define Book Class which is of Product type.&nbsp; &nbsp; /// </summary>&nbsp; &nbsp; internal class Book : Product&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Book specific data&nbsp; &nbsp; &nbsp; &nbsp; public Book(int price)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.Price = price;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public override void Accept(IVisitor visitor)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; visitor.Visit(this);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; /// <summary>&nbsp; &nbsp; /// Define Car Class which is of Product type.&nbsp; &nbsp; /// </summary>&nbsp; &nbsp; internal class Car : Product&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Car specific data&nbsp; &nbsp; &nbsp; &nbsp; public Car(int price)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.Price = price;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public override void Accept(IVisitor visitor)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; visitor.Visit(this);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; /// <summary>&nbsp; &nbsp; /// Define Wine Class which is of Product type.&nbsp; &nbsp; /// </summary>&nbsp; &nbsp; internal class Wine : Product&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Wine specific data&nbsp; &nbsp; &nbsp; &nbsp; public Wine(int price)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.Price = price;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public override void Accept(IVisitor visitor)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; visitor.Visit(this);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; #endregion "Structure Implementations"&nbsp;&nbsp;创建一个访问者界面并实现它:/// <summary>/// Define basic Visitor Interface./// </summary>internal interface IVisitor{&nbsp; &nbsp; void Visit(Book book);&nbsp; &nbsp; void Visit(Car car);&nbsp; &nbsp; void Visit(Wine wine);}#region "Visitor Implementation"/// <summary>/// Define Visitor of Basic Tax Calculator./// </summary>internal class BasicPriceVisitor : IVisitor{&nbsp; &nbsp; public int taxToPay { get; private set; }&nbsp; &nbsp; public int totalPrice { get; private set; }&nbsp; &nbsp; public void Visit(Book book)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var calculatedTax = (book.Price * 10) / 100;&nbsp; &nbsp; &nbsp; &nbsp; totalPrice += book.Price + calculatedTax;&nbsp; &nbsp; &nbsp; &nbsp; taxToPay += calculatedTax;&nbsp; &nbsp; }&nbsp; &nbsp; public void Visit(Car car)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var calculatedTax = (car.Price * 30) / 100;&nbsp; &nbsp; &nbsp; &nbsp; totalPrice += car.Price + calculatedTax;&nbsp; &nbsp; &nbsp; &nbsp; taxToPay += calculatedTax;&nbsp; &nbsp; }&nbsp; &nbsp; public void Visit(Wine wine)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var calculatedTax = (wine.Price * 32) / 100;&nbsp; &nbsp; &nbsp; &nbsp; totalPrice += wine.Price + calculatedTax;&nbsp; &nbsp; &nbsp; &nbsp; taxToPay += calculatedTax;&nbsp; &nbsp; }}#endregion "Visitor Implementation"执行:&nbsp;static void Main(string[] args)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; Program.ShowHeader("Visitor Pattern");&nbsp; &nbsp; &nbsp; &nbsp; List<Product> products = new List<Product>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Book(200),new Book(205),new Book(303),new Wine(706)&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; ShowTitle("Basic Price calculation");&nbsp; &nbsp; &nbsp; &nbsp; BasicPriceVisitor pricevisitor = new BasicPriceVisitor();&nbsp; &nbsp; &nbsp; &nbsp; products.ForEach(x =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x.Accept(pricevisitor);&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine("");&nbsp; &nbsp; }&nbsp; &nbsp; &nbsp;

慕妹3146593

当你有一个多态类型并且你想根据对象的特定子类型执行外部定义的操作时,通常使用访问者模式。在您的示例中,CoursesResult是一个多态类型,访问者允许您将Successful响应转换为一个,OkObjectResult而无需直接耦合这两种类型。您CoursesResult直接返回 an 的替代方法IActionResult是传统的多态性,它更简单,但将域逻辑耦合到 MVC 层。现在,我不知道您的全套响应是什么样的,但是如果您只有一个成功响应,其余都是错误,那么这里最简单的方法是直接返回成功响应并为其他情况抛出异常:public async Task<CourseList> GetCourses(UserSession userSession) {&nbsp; return courseList; /* or */ throw new BadRequestException();}然后您的控制器可以简单地捕获异常并将它们转换为适当的IActionResult.
随时随地看视频慕课网APP
我要回答