−using System;
using System.Collections.Generic;
using System.Linq;
Handler chain = new BillingHandler(new TechHandler(null));
foreach (string kind in new[] { "technical", "other" })
{
Reply result = chain.Handle(new Ticket(kind));
Console.WriteLine(result.Handled + ": " + result.Message);
}
sealed record Ticket(string Kind);
sealed record Reply(bool Handled, string Message);
abstract class Handler(Handler? next)
{
public Reply Handle(Ticket ticket)
{
Reply? result = TryHandle(ticket);
if (result is not null) return result;
return next?.Handle(ticket) ?? new Reply(false, "unhandled: " + ticket.Kind);
}
protected abstract Reply? TryHandle(Ticket ticket);
}
sealed class BillingHandler(Handler? next) : Handler(next)
{
protected override Reply? TryHandle(Ticket ticket) =>
ticket.Kind == "billing" ? new Reply(true, "billing desk") : null;
}
sealed class TechHandler(Handler? next) : Handler(next)
{
protected override Reply? TryHandle(Ticket ticket) =>
ticket.Kind == "technical" ? new Reply(true, "technical desk") : null;
}
+using System;
using System.Collections.Generic;
using System.Linq;
Handler chain = new BillingHandler(new TechHandler(null));
foreach (string kind in new[] { "technical", "other" })
{
Reply result = chain.Handle(new Ticket(kind));
Console.WriteLine(result.Handled + ": " + result.Message);
}
sealed record Ticket(string Kind);
sealed record Reply(bool Handled, string Message);
// Keep acceptance rules in handlers and share the forwarding flow in the base class.
abstract class Handler(Handler? next)
{
public Reply Handle(Ticket ticket)
{
Reply? result = TryHandle(ticket);
if (result is not null) return result;
// null means this handler declines the ticket, so pass it to the next handler.
// If there is no successor, return Handled=false for the whole chain.
return next?.Handle(ticket) ?? new Reply(false, "unhandled: " + ticket.Kind);
}
protected abstract Reply? TryHandle(Ticket ticket);
}
// Decline with null without choosing the next handler here.
sealed class BillingHandler(Handler? next) : Handler(next)
{
protected override Reply? TryHandle(Ticket ticket) =>
ticket.Kind == "billing" ? new Reply(true, "billing desk") : null;
}
sealed class TechHandler(Handler? next) : Handler(next)
{
protected override Reply? TryHandle(Ticket ticket) =>
ticket.Kind == "technical" ? new Reply(true, "technical desk") : null;
}