Reputation: 3506
Let's say I have an object class (widgetBlue
). This object class fulfills an interface (iWidgetBlue
) and inherits from an abstract class (widget
). widgetBlue
does NOT have an explicitly coded constructor and has information needed to perform actions against it.
I want to be able to create an instance of widgetBlue
in WidgetService
to be returned to the consumer so that they can work with it but not allow the consumer to create an instance of widgetBlue
out of the blue. WidgetService
needs to be able to create a new widgetBlue
and instantiate its properties.
So this would be okay:
WidgetBlue retVal = SomeRemoteMethodThatReturnsAWidgetBlue();
But this would not be okay:
WidgetBlue retVal = new WidgetBlue();
Edit: Furthermore, the widget objects are all in their own project and referenced by both the consumer and the service.
How would I do this?
Upvotes: 0
Views: 111
Reputation: 26398
You could do it with the builder pattern:
public Builder
{
bool _prop = false;
public Builder WithProperty(bool prop)
{
_prop = prop;
return this;
}
public Widget Build(){
if(prop)
return new FooWidget();
else
return new BarWidget();
}
}
public abstract class Widget()
{
}
public class FooWidget: Widget{}
public class BarWidget: Widget{}
You cannot instantiate the abstract Widget, and you hide the actual choice of higher implementation behind an abstraction.
Upvotes: 0
Reputation: 3589
I usually accomplish stuff like this by hiding the concrete class in some other assembly. Make WidgetBlue
an internal class, then you can supply instances of it from a WidgetFactory
that creates IWidget
s (you can have a BuildBlue()
method and you can easily extend it to provide red ones as well later if you want). This completely decouples clients from your concrete implementation. It's called the interface segregation principle.
namespace Widgets
{
public interface IWidget
{
}
internal abstract class Widget : IWidget
{
}
internal class BlueWidget : Widget
{
}
public class WidgetFactory
{
public IWidget BuildBlue()
{
return new BlueWidget();
}
}
}
In some other project:
using Widgets;
namespace Client
{
public class Client
{
public static void Main(string[] args)
{
IWidget blueWidget = new WidgetFactory().BuildBlue();
IWidget otherBlueWidget = new BlueWidget(); // doesn't compile
}
}
}
Upvotes: 2
Reputation: 35270
If I'm understanding your question correctly, you could just create a parameter-less constructor in WidgetBlue
and set it to have an internal
access modifier. That way, you could only create new instances from classes within the same assembly (e.g. your WidgetService
class) and not from your consumer which I'm assuming is an external assembly.
Upvotes: 2
Reputation: 62213
A better approach is to use Interfaces so the concrete class is abstracted from the consumer and even hidden if you mark the concrete class as internal. An interface is a contract so there is no concept of an instance of an interface / ie. interface constructor.
Your example would then be.
internal class WidgetBlue : IWidgetBlue {}
IWidgetBlue retVal = SomeRemoteMethodThatReturnsAIWidgetBlue();
And this is not possible
IWidgetBlue retVal = new IWidgetBlue();
It also allows you to change the underlying implementation in the future or extend it as you see fit.
Upvotes: 0