user4593252
user4593252

Reputation: 3506

Possible to create a class that can only be created by certain objects?

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

Answers (4)

Meirion Hughes
Meirion Hughes

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

sara
sara

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 IWidgets (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

rory.ap
rory.ap

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

Igor
Igor

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

Related Questions