I'm creating many builders where I use inheritance.
My resources have many properties and are stored in a Repository.
In rare case I need to update them.
When I update, I need to keep the same objectId
(I track update on the repository).
I use the same Builder/Updater as it's easier for my users (there are more than 10 concrete builders).
The code with only one builder (and properties removed):
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()
{
}
}
The main problem with this approach is for the Update()
:
var colorResource2 = new ColorResourceBuilder(colorResource1).Name("Blue").Update();
colorResource2 != colorResource1
=> two different object have the same Id...
hypothetical improvement:
var colorResource2 = new ColorResourceBuilder(ref colorResource1).Name("Blue").Update();
var colorResource2 = new ColorResourceBuilder(ref colorResource1).Name("Blue").Build();
It could be OK for the Update()
. But weird with Build()
as ref
suggest update.
Another hypothetical improvement:
var colorResource2 = new ColorResourceBuilder().Name("Blue").Update(ref colorResource1);
var colorResource2 = new ColorResourceBuilder(colorResource1).Name("Blue").Build();
Will incur another usage inconsistency problem.
I'm looking for any advice to make it more clean and natural. Or any other pattern which could do the job.