[C# 디자인 패턴] 재귀 제네릭을 사용한 Fluent Builder 패턴
- C#
- 2022. 10. 31. 06:19
참고
Fluent Builder 상속 문제
- Fluent Builder 패턴을 이용하여 프로그래밍을 하다 보면, 상속 문제에 부딪히게 됩니다.
- 예제를 통해 보여 드리도록 하겠습니다.
- Employee 객체를 만들고 싶다고 가정합니다.
public class Employee
{
public string Name { get; set; }
public string Position { get; set; }
public double Salary { get; set; }
public override string ToString()
{
return $"Name: {Name}, Position: {Position}, Salary: {Salary}";
}
}
- Employee 모델 클래스를 만들었고, 여기서 Name 속성에 값을 바인딩 하는 Set 메서드를 Builder 패턴으로 만든다고 가정합니다.
public class EmployeeInfoBuilder
{
protected Employee employee = new Employee();
public EmployeeInfoBuilder SetName(string name)
{
employee.Name = name;
return this;
}
}
- 이제 EmployeePositionBuilder 클래스를 생성 후, EmployeeInfoBuilder 클래스를 상속 받습니다.
public class EmployeePositionBuilder: EmployeeInfoBuilder
{
public EmployeePositionBuilder AtPosition(string position)
{
employee.Position = position;
return this;
}
}
- 마지막으로
Program.cs
에서 해당 빌더 클래스 객체 생성 후 메서드를 호출합니다.
- 하지만, 위 이미지에서 보다시피 객체 생성을 할 수 없습니다.
- 이유는 메서드가 현제 메서드를 구현하거나 상속하지 않는
SetName
유형의 인스턴스를 반환하기 때문입니다. - 현재 해당 문제를 해결 하려면, 파생 클래스에서 기본 클래스로 정보를 전달하는 솔루션으로 변경해야 합니다.
- 그러기 위해서는 재귀 제네릭 접근 방식 을 사용해야 합니다.
Fluent Builder로 재귀 제네릭 구현하기
- 따라서 EmployeeBuilder직원 개체를 인스턴스화하고 제공하는 역할을 하는 추상 클래스부터 시작하겠습니다.
public abstract class EmployeeBuilder
{
protected Employee employee;
public EmployeeBuilder()
{
employee = new Employee();
}
public Employee Build() => employee;
}
- EmployeeBuilder 추상 클래스를 생성 하였다면, 다음 EmployeeInfoBuilder 클래스를 제네렉 형식으로 수정합니다.
public class EmployeeInfoBuilder<T>: EmployeeBuilder where T: EmployeeInfoBuilder<T>
{
public T SetName(string name)
{
employee.Name = name;
return (T)this;
}
}
namespace ConsoleApp1;
public class EmployeePositionBuilder<T> : EmployeeInfoBuilder<EmployeePositionBuilder<T>> where T : EmployeePositionBuilder<T>
{
public T AtPosition(string position)
{
employee.Position = position;
return (T)this;
}
}
- 이렇게 함으로써 두 클래스 모두에서 상속을 가능하게 됐습니다.
- 만약, 직원이 급여를 필요로 한다면 EmployeeSalaryBuilder 클래스를 생성하여 WithSalary 메서드를 쉽게 추가할 수 있습니다.
public class EmployeeSalaryBuilder<T>: EmployeePositionBuilder<EmployeeSalaryBuilder<T>> where T: EmployeeSalaryBuilder<T>
{
public T WithSalary(double salary)
{
employee.Salary = salary;
return (T)this;
}
}
- 여기까지 해서 현재 재귀 제네릭으로 Builder 클래스를 만들었습니다.
- 하지만, 아직은 객체를 생성할 수는 없습니다.
- 이유는 객체 생성을 할때 타입이 명확하지가 않기 때문입니다.
- 최종적으로 Builder 객체를 빌드할 수 있는 API를 생성해야 합니다.
- 코드는 다음과 같습니다.
public class EmployeeBuilderDirector : EmployeeSalaryBuilder<EmployeeBuilderDirector>
{
public static EmployeeBuilderDirector NewEmployee => new EmployeeBuilderDirector()
}
- EmployeeBuilderDirector API 클래스를 생성 후, 최종적으로 다음과 같이 Main 함수에 Builder 객체를 생성하여 사용할 수 있습니다.
class Program
{
static void Main(string[] args)
{
var emp = EmployeeBuilderDirector
.NewEmployee
.SetName("Maks")
.AtPosition("Software Developer")
.WithSalary(3500)
.Build();
Console.WriteLine(emp);
}
}
- 위와 같이 재귀 제네릭 방법을 이용하여 연속적으로 상속을 받아서 최종적으로 Flunet Builder 패턴 클래스를 작성할 수 있습니다.
728x90
'C#' 카테고리의 다른 글
[.NET EFCore] EFCore Postgresql Database First 예시 (0) | 2022.11.26 |
---|---|
[C# 디자인패턴] Factory Method 패턴 (0) | 2022.11.01 |
[C# 디자인 패턴] 빌더 디자인 패턴 및 Fluent Builder (0) | 2022.10.28 |
[C#] 분산 추적 이란? (0) | 2022.07.29 |
[C#] dotnet Memory 누수 체크 (0) | 2022.07.22 |
이 글을 공유하기