我试图了解在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);
}
}
答案 0 :(得分:1)
在代码项目-Visitor Pattern ReExplained中对此进行了广泛的研究。
我将提供标题。
在这里,游客模式通过两种方式解决问题:
现在这两个方面彼此独立,并且不应相互混淆。因此,这就是所有关于OOP的主体,即单一职责主体,将您带回到SOLID architecture。
此功能的主要参与者是:
现在,所有这些模式的目标,关键是,是创建功能受限的数据模型以及具有将对数据进行操作的具有特定功能的一组访问者。该模式允许访问者将对象作为参数传递给访问者方法,从而访问数据结构的每个元素。
毕竟的好处-
将算法与数据模型分离的关键是轻松添加新行为的能力。数据模型的类是使用称为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
。