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

时间:2019-01-05 20:40:50

标签: c# design-patterns .net-core visitor visitor-pattern

我试图了解在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

IVisitor

    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);
        }
    }

2 个答案:

答案 0 :(得分:1)

在代码项目-Visitor Pattern ReExplained中对此进行了广泛的研究。

我将提供标题。

在这里,游客模式通过两种方式解决问题:

  • 有一个迭代机制,它知道如何在Object上迭代 hirerachy.it对对象中的行为一无所知 层次结构。
  • 需要实施的新行为一无所知 迭代机制,他们不知道如何迭代对象 等级。

现在这两个方面彼此独立,并且不应相互混淆。因此,这就是所有关于OOP的主体,即单一职责主体,将您带回到SOLID architecture


此功能的主要参与者是:

  • 访问者-定义“访问”操作的界面。这是 访问者模式的核心。它为每种类型定义了一个访问操作 对象结构中的Concreate Element的设置。
  • ConcreateVisitor -实现访问者中定义的操作 界面。
  • ElementBase :它是定义接受的抽象/接口 以访问者为参数的操作。
  • ConcreateElement -这些类型实现Element的Accept方法 界面。
  • 对象结构-它将数据结构的所有元素都保存为 可以被枚举和使用的集合,列表或其他东西 访客。它为所有访客提供访问其界面 元件。这些元素包括称为“接受”的方法。 然后枚举集合

现在,所有这些模式的目标,关键是,是创建功能受限的数据模型以及具有将对数据进行操作的具有特定功能的一组访问者。该模式允许访问者将对象作为参数传递给访问者方法,从而访问数据结构的每个元素。


毕竟的好处-

将算法与数据模型分离的关键是轻松添加新行为的能力。数据模型的类是使用称为Visit的通用方法创建的,该方法可以在运行时接受visitor对象。然后可以创建其他访问者对象并将其传递给此方法,然后该方法将回调自身作为参数传递给该访问者方法。

值得一提的另一件事是

在对象层次结构中添加新类型需要对所有访问者进行更改,这应该被视为一种优势,因为它肯定会迫使我们将新类型添加到保留了某些特定于类型代码的所有位置。基本上,它不只是让您忘记这一点。

访客模式仅有用:

  • 如果要实现的接口是静态的,并且不是 改变很多。
  • 如果预先知道所有类型,即在设计时所有对象 必须知道。

在底行:

访客实现以下设计原则

  • 关注分离-访问者模式促进了这一原则, 多个方面/问题分为多个其他类别,例如 它鼓励更干净的代码和代码可重用性,并且代码是 更具可测试性。
  • 单一责任原则-访问者模式也强制执行 原理。一个对象几乎应该承担一个责任。无关 行为必须与之分离开来。
  • 开放关闭原则-访问者模式也遵循此原则, 好像,我们要扩展对象行为一样,原始源代码 不会改变。访客模式为我们提供了 将其分离到另一个类,并将这些操作应用于对象 在运行时。

访问者实施的好处

  • 将数据结构的行为与其分开。访客分开 创建对象来实现这种行为。
  • 它解决了很少遇到但有 重要的影响。

您可以更深入地了解本文,以了解本文的全部含义,但是如果我要举一个例子:

首先,我们将定义称为IVisitable的接口。它将定义一个接受方法,该方法将接受IVisitor的参数。该界面将作为产品列表中所有类型的基础。像Book,Car和Wine这样的所有类型(在我们的示例中)都将实现此类型。

/// <summary>
/// Define Visitable Interface.This is to enforce Visit method for all items in product.
/// </summary>
internal interface IVisitable
{
    void Accept(IVisitor visit);
}   

然后我们将实现它:

  #region "Structure Implementations"


    /// <summary>
    /// Define base class for all items in products to share some common state or behaviors.
    /// Thic class implement IVisitable,so it allows products to be Visitable.
    /// </summary>
    internal abstract class Product : IVisitable
    {
        public int Price { get; set; }
        public abstract void Accept(IVisitor visit);
    }

    /// <summary>
    /// Define Book Class which is of Product type.
    /// </summary>
    internal class Book : Product
    {
        // Book specific data

        public Book(int price)
        {
            this.Price = price;
        }
        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Define Car Class which is of Product type.
    /// </summary>
    internal class Car : Product
    {
        // Car specific data

        public Car(int price)
        {
            this.Price = price;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    /// <summary>
    /// Define Wine Class which is of Product type.
    /// </summary>
    internal class Wine : Product
    {
        // Wine specific data
        public Wine(int price)
        {
            this.Price = price;
        }

        public override void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

    #endregion "Structure Implementations"  

创建访问者界面并实现它:

/// <summary>
/// Define basic Visitor Interface.
/// </summary>
internal interface IVisitor
{
    void Visit(Book book);
    void Visit(Car car);
    void Visit(Wine wine);
}

#region "Visitor Implementation"


/// <summary>
/// Define Visitor of Basic Tax Calculator.
/// </summary>
internal class BasicPriceVisitor : IVisitor
{
    public int taxToPay { get; private set; }
    public int totalPrice { get; private set; }

    public void Visit(Book book)
    {
        var calculatedTax = (book.Price * 10) / 100;
        totalPrice += book.Price + calculatedTax;
        taxToPay += calculatedTax;
    }

    public void Visit(Car car)
    {
        var calculatedTax = (car.Price * 30) / 100;
        totalPrice += car.Price + calculatedTax;
        taxToPay += calculatedTax;
    }

    public void Visit(Wine wine)
    {
        var calculatedTax = (wine.Price * 32) / 100;
        totalPrice += wine.Price + calculatedTax;
        taxToPay += calculatedTax;
    }
}


#endregion "Visitor Implementation"

执行:

 static void Main(string[] args)
    {
        Program.ShowHeader("Visitor Pattern");

        List<Product> products = new List<Product>
        { 
            new Book(200),new Book(205),new Book(303),new Wine(706)
        };

        ShowTitle("Basic Price calculation");
        BasicPriceVisitor pricevisitor = new BasicPriceVisitor();
        products.ForEach(x =>
        {
            x.Accept(pricevisitor);
        });

        Console.WriteLine("");
    }     

答案 1 :(得分:1)

访问者模式通常在具有多态类型并且要基于对象的特定子类型执行外部定义的操作时使用。在您的示例中,CoursesResult是多态类型,访问者可让您将Successful响应转换为OkObjectResult,而无需直接将这两种类型耦合。

CoursesResult直接返回IActionResult的替代方法是传统的多态性,它比较简单,但是将域逻辑耦合到MVC层。

现在,我不知道您完整的响应集是什么样的,但是如果您只有一个成功的响应而其余的都是错误,那么这里最简单的方法是直接返回成功的响应并为该响应抛出异常其他情况:

public async Task<CourseList> GetCourses(UserSession userSession) {
  return courseList; /* or */ throw new BadRequestException();
}

然后,您的控制器可以简单地捕获异常并将其转换为适当的IActionResult