Builder Pattern
- Separate the construction of an object from its representation
Classical Structure
Scenario
- Export power point slide to PDF, Movie etc
Problem
public class Slide
{
public string Text { get; init; }
public Slide(string text)
{
Text = text;
}
}
public class PdfDocument
{
public void AddPage(string text)
{
Console.WriteLine("Adding a page to pdf");
}
}
public class Movie
{
public void AddFrame(string text, int duration)
{
Console.WriteLine("Adding a frame to movie");
}
}
public enum PresentationFormat
{
PDF,
Movie
}
public class Presentation
{
List<Slide> slides = new List<Slide>();
public void AddSlide(Slide slide)
{
slides.Add(slide);
}
public void Export(PresentationFormat presentationFormat)
{
if (presentationFormat == PresentationFormat.PDF)
{
PdfDocument pdfDocument = new PdfDocument();
foreach (Slide slide in slides)
{
pdfDocument.AddPage(slide.Text);
}
}
else if (presentationFormat == PresentationFormat.Movie)
{
Movie movie = new Movie();
foreach (Slide slide in slides)
{
movie.AddFrame(slide.Text, 10);
}
}
}
}
- Violates Open Closed Principle
- Tightly Coupled
- Presentation is aware of the inner details of other classes
- Duplicate logic
Solution
public interface IPresentationBuilder
{
void AddSlide(Slide slide);
}
public class MovieBuilder : IPresentationBuilder
{
Movie movie = new Movie();
public void AddSlide(Slide slide)
{
movie.AddFrame(slide.Text, 10);
}
public Movie getMovie() { return movie; }
}
public class PdfDocumentBuilder : IPresentationBuilder
{
PdfDocument pdfDocument = new PdfDocument();
public void AddSlide(Slide slide)
{
pdfDocument.AddPage(slide.Text);
}
public PdfDocument GetPdfDocument() => pdfDocument;
}
public class Presentation
{
List<Slide> slides = new List<Slide>();
public void AddSlide(Slide slide)
{
slides.Add(slide);
}
public void Export(IPresentationBuilder builder)
{
foreach (var slide in slides)
{
builder.AddSlide(slide);
}
}
}
Example Structure
Example Code