>

상속을 사용하는 빌더를 많이 만들고 있습니다.

내 리소스에는 많은 속성이 있으며 리포지토리에 저장됩니다. 드문 경우지만 업데이트해야합니다. 업데이트 할 때 동일한 objectId 를 유지해야합니다  (저장소에서 업데이트를 추적합니다.)

사용자에게 더 쉬운 것과 동일한 Builder/Updater를 사용합니다 (구체적인 빌더가 10 명 이상임).

하나의 빌더 만있는 코드(및 속성이 제거됨) :

    public interface IBuilder<T, P>
        {
            P Build();
            P Update();
        }

   public abstract class BuilderBase<T, P>: IBuilder<T, P> 
        where T : BuilderBase<T, P>
        where P : class, new()
        {
            protected P Result;
            protected P Source;
            protected T This;
            protected BuilderBase()
            {
                Result = new P();
                This = (T) this;
            }
            protected BuilderBase(P source):this()
            {
                Source = source;
            }
            public P Build()
            {
                var result = Result;
                Result = null;
                return result;
            }
            public abstract P Update();
    }

  public abstract class ResourceBuilder<T, P> : BuilderBase<T, P>
        where T : ResourceBuilder<T, P>
        where P : ResourceBase, new()
        {
            protected ResourceBuilder():base(){}
            protected ResourceBuilder(P resource):base(resource)
            {
                Result.Name = Source.Name;
            }
            public new P Build()
            {
                var result = Result;
                return base.Build();
            }
            public override P Update()
            {
                if (Source != null)
                    Result.ResourceId = Source.ResourceId; 
                return Build();
            }
            public T Name(string name)
            {
                Result.Name = name;
                return This;
            }
        }

   public abstract class ColorResourceBuilder<T, P> : ResourceBuilder<T, P>
           where T : ColorResourceBuilder<T, P>
           where P : ColorResource, new()
    {
        public T Color(Color color)
        {
            Result.Color = color;
            return This;
        }
        protected ColorResourceBuilder(P colorResource) : base(colorResource)
        {
            Result.Color = Source.Color;
        }
        protected ColorResourceBuilder() : base()
        {
        }
    }

      public class ColorResourceBuilder : ColorResourceBuilder<ColorResourceBuilder, ColorResource> {
        public ColorResourceBuilder(ColorResource colorResource) : base(colorResource)
        {
        }
        public ColorResourceBuilder()
        {
        }
    }

이 접근법의 주요 문제점은 Update() 입니다. :

var colorResource2 = new ColorResourceBuilder(colorResource1).Name("Blue").Update();

colorResource2 != colorResource1   =>두 개의 다른 객체가 동일한 ID를 가지고 있습니다 ...

가설 개선 :

var colorResource2 = new ColorResourceBuilder(ref colorResource1).Name("Blue").Update();
var colorResource2 = new ColorResourceBuilder(ref colorResource1).Name("Blue").Build();

와이즈 비즈에게는 괜찮을 수도있다 . 그러나 Update() 와 이상   Build() 로  업데이트 제안.

또 다른 가설 개선 :

ref

다른 사용 불일치 문제가 발생합니다.

더 깨끗하고 자연스럽게 만드는 조언을 찾고 있습니다. 또는 일을 할 수있는 다른 패턴.

var colorResource2 = new ColorResourceBuilder().Name("Blue").Update(ref colorResource1); var colorResource2 = new ColorResourceBuilder(colorResource1).Name("Blue").Build();
  • 답변 # 1

    빌더 패턴에 대한 주석

    Joshua Bloch가 새로운 버전의 빌더 패턴을 발견했다고 생각하지 않습니다. GoF의 표준 방식과 목적을 따르는 것이 좋습니다.

    빌더 패턴의 목적은 다음과 같습니다 :

    <올>

    생성자 매개 변수를 많이 사용하지 마십시오

    항상 객체를 만들 수 있도록 기본값을 제공하고 일관성을 유지

    유연하게 읽을 수있는 코드 만들기

    여기서는 패턴이 적절하지 않으며 원래의 방식으로 구현되지 않았다고 생각합니다. 예를 들어 Update ()-방법은 빌더 패턴과 관련이 없습니다.

    의도에 대한 추측 "리포지토리"를 언급했듯이 일종의 지속성 컨텍스트를 다루고 있습니다. 구현에서 build ()-method는 저장소에 새 객체를 만들고 update ()-method는 지금까지 저장소의 기존 객체를 업데이트합니다.

    제안, 생성 및 결과 내가 따르는 디자인은 자연스러운 접근 방식입니다.

    새 리소스를 생성하려면 생성 프로세스 중에 고려할 수있는 데이터가 포함 된 제안서 개체를 생성합니다. 제안서 객체 자체는 빌더 패턴으로 구성되었을 수 있습니다. 처음에 언급 된 목적에 따라 다릅니다.

    그 후 제안서 객체는 생성 과정으로 전달됩니다. 내부 시스템 일관성에 대해 유효성을 검사하고 검사합니다. 작성자 객체는 원하는 객체 (SRP) 생성을 담당하는 것으로 잘 정의되어 있습니다.

    유효성 검사 오류가 발생하지 않고 시스템 일관성을 위반하지 않으면 개체가 생성 및 유지되지 않습니다. 오브젝트는 빌더 패턴을 통해 내부적으로 (책임 오브젝트 내) 구성 될 수 있습니다. 그러나 그것은 끈기와 아무런 관련이 없습니다.

    제안, 업데이트 및 결과

    업데이트와 동일합니다. 유일한 차이점은 업데이트 제안, 업데이트 할 기존 개체 및 업데이트 프로세스를 수행 할 책임있는 개체가 있다는 것입니다.

    이제 흥미로워지고 있습니다. 업데이트 결과는 버전이 지정된 새 객체 x 또는 캐시 된 이전 객체 일 수 있습니다. 불변성으로 작업하고 싶은지 아닌지에 따라 다릅니다. "id"가 있으면 객체를 캐시하고 변경하는 것이 좋습니다.

    그럼에도 불구하고 두 시나리오에서 equals와 hashcode를 재정의해야합니다. 그러나 ID가 동일한 경우 모든 버전의 두 객체가 동일합니다.

    결론 <올>

    빌더 패턴이 변경 가능한 오브젝트를 리턴하지 않도록하고 항상 새 오브젝트를 리턴하십시오. "빌더"패턴은 무언가를 업데이트하지 않는 것을 "빌드"하기위한 것입니다.

    일시적으로 만 빌드, 빌더 패턴에서 지속성을 포함하지 않음

    영구적 객체 (비즈니스 객체 ??)와 잘 정의 된 책임을위한 CRUD 운영을위한 적절한 디자인을 가지고 있습니다

    제안서, 제작자/갱신 자/삭제 자와 결과 구분하기

    죄송합니다. 패턴 문제보다는 문제 도메인의 디자인 문제입니다.

  • 이전 algorithm - 고유 한 정수 합
  • 다음 java - 웹 스크래핑 앱의 브릿지 디자인 패턴 구현 - 후속 조치