Skip to content

Instantly share code, notes, and snippets.

@NTCoding
Last active November 25, 2018 12:14
Show Gist options
  • Select an option

  • Save NTCoding/c773da292428255fe9f9795d6c0a5d17 to your computer and use it in GitHub Desktop.

Select an option

Save NTCoding/c773da292428255fe9f9795d6c0a5d17 to your computer and use it in GitHub Desktop.
public abstract class Comment
{
public static ProposedComment Parse(String proposedComment)
{
return new ProposedComment(proposedComment);
}
}
public class ProposedComment : Comment
{
public ProposedComment(String value)
{
Value = value;
}
public Value { get; }
}
public abstract class ReviewedComment : Comment
{
...
}
public class CleanComment : ReviewedComment
{
...
}
public class ProfaneComment : ReviewedComment
{
...
}
public interface ReviewComment
{
ReviewedComment Review(ProposedComment comment): ReviewedComment;
}
public class Program
{
ReviewComment rc;
public static void Main(String[] args)
{
// As a caller, all I need to know is the Comment.Parse method. The type system guides me from here
ProposedComment p = Comment.Parse("comment");
ReviewedComment r = rc.Review(p);
// Make all states explicit and handle them at compile time. Avoid throwing hidden exceptions at runtime.
switch (r)
{
case CleanComment cl:
...
case ProfaneComment pr:
...
}
}
}
@NTCoding

NTCoding commented Nov 25, 2018

Copy link
Copy Markdown
Author

Key things I want to express in this pattern:

  1. Each state is represented by a type, even 'invalid' states
  2. The compiler is aware of these states and encourages us to handle them at compile time not runtime (with ADTs in Scala or DUs in F#, the compiler could ensure we handle these cases)
  3. Callers of methods do not have to worry about implicit exceptions being thrown
  4. What we originally thought was factory logic (constructing and validating Comment) has been broken down into: creating an initial state and applying a domain service to produce to the next state. This makes the 'ReviewComment' domain rule more explicit rather than implicit factory logic.

ghost commented Nov 25, 2018

Copy link
Copy Markdown

I'd go for var p = ProposedComment.Parse("comment"); putting the Parse on ProposedComment. Because that's what you're starting out with. Why do ProposedComment and ReviewedComment share a base type? I'd totally decouple unless there's some behavior that needs both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment