- Advanced TypeScript Programming Projects
- Peter O'Hanlon
- 513字
- 2021-06-24 13:27:10
Applying the visitor pattern to our code
Now that we know what the visitor pattern is, let's take a look at how we are going to apply it to our code:
- First, we are going to create the IVisitor and IVisitable interfaces as follows:
interface IVisitor {
Visit(token : ParseElement, markdownDocument : IMarkdownDocument) : void;
}
interface IVisitable {
Accept(visitor : IVisitor, token : ParseElement, markdownDocument : IMarkdownDocument) : void;
}
- When our code reaches the point where Visit is called, we are going to use the TagTypeToHtml class to add the relevant opening HTML tag, the line of text, and then the matching closing HTML tag to our MarkdownDocument. As this is common to each of our tag types, we can implement a base class that encapsulates this behavior, as follows:
abstract class VisitorBase implements IVisitor {
constructor (private readonly tagType : TagType, private readonly TagTypeToHtml : TagTypeToHtml) {}
Visit(token: ParseElement, markdownDocument: IMarkdownDocument): void {
markdownDocument.Add(this.TagTypeToHtml.OpeningTag(this.tagType), token.CurrentLine,
this.TagTypeToHtml.ClosingTag(this.tagType));
}
}
- Next, we need to add the concrete visitor implementations. This is as simple as creating the following classes:
class Header1Visitor extends VisitorBase {
constructor() {
super(TagType.Header1, new TagTypeToHtml());
}
}
class Header2Visitor extends VisitorBase {
constructor() {
super(TagType.Header2, new TagTypeToHtml());
}
}
class Header3Visitor extends VisitorBase {
constructor() {
super(TagType.Header3, new TagTypeToHtml());
}
}
class ParagraphVisitor extends VisitorBase {
constructor() {
super(TagType.Paragraph, new TagTypeToHtml());
}
}
class HorizontalRuleVisitor extends VisitorBase {
constructor() {
super(TagType.HorizontalRule, new TagTypeToHtml());
}
}
At first, this code may seem like overkill, but it serves a purpose. If we take Header1Visitor, for instance, we have a class that has the single responsibility of taking the current line and adding it to our markdown document wrapped in H1 tags. We could litter our code with classes that were responsible for checking whether the line started with #, and then remove the # from the start, prior to adding the H1 tags and the current line. However, that makes the code harder to test and more likely to break, especially if we want to change the behavior. Also, the more tags we add, the more fragile this code will become.
The other side of the visitor pattern code is the IVisitable implementation. For our current code, we know that we want to visit the relevant visitor whenever we call Accept. What this means to our code is that we can have a single visitable class that implements our IVisitable interface. This is shown in the following code:
class Visitable implements IVisitable {
Accept(visitor: IVisitor, token: ParseElement, markdownDocument: IMarkdownDocument): void {
visitor.Visit(token, markdownDocument);
}
}
- Linux運維之道(第3版)
- 電腦組裝與系統安裝
- pcDuino開發實戰
- Linux實戰
- 鴻蒙生態:開啟萬物互聯的智慧新時代
- Linux網絡操作系統與實訓(第三版)
- Instant Handlebars.js
- Installing and Configuring Windows 10:70-698 Exam Guide
- Extending Bootstrap
- Linux操作系統應用編程
- AutoCAD 2014中文版從入門到精通
- Linux軟件管理平臺設計與實現
- Agile IT Security Implementation Methodology
- Docker容器技術與應用
- Getting Started with UDK