views:

3270

answers:

9

Recently I've been thinking about securing some of my code. I'm curious how one could make sure an object can never be created directly, but only via some method of a factory class. Let us say I have some "business object" class and I want to make sure any instance of this class will have a valid internal state. In order to achieve this I will need to perform some check before creating an object, probably in its constructor. This is all okay until I decide I want to make this check be a part of the business logic. So, how can I arrange for a business object to be creatable only through some method in my business logic class but never directly? The first natural desire to use a good old "friend" keyword of C++ will fall short with C#. So we need other options...

Let's try some example:

public MyBusinessObjectClass
{
    public string MyProperty { get; private set; }

    public MyBoClass (string myProperty)
    {
        MyProperty = myProperty;
    }
}

public MyBusinessLogicClass
{
    public MyBusinessObjectClass CreateBusinessObject (string myProperty)
    {
        // Perform some check on myProperty

        if (true /* check is okay */)
            return new MyBusinessObjectClass (myProperty);

        return null;
    }
}

It's all okay until you remember you can still create MyBusinessObjectClass instance directly, without checking the input. I would like to exclude that technical possibility altogether.

So, what does the community think about this?

+8  A: 

You could make the constructor on your MyBusinessObjectClass class internal, and move it and the factory into their own assembly. Now only the factory should be able to construct an instance of the class.

Matt Hamilton
+15  A: 

You can make the constructor private, and the factory a nested type:

public class BusinessObject
{
    private BusinessObject(string property)
    {
    }

    public class Factory
    {
        public static BusinessObject CreateBusinessObject(string property)
        {
            return new BusinessObject(property);
        }
    }
}

This works because nested types have access to the private members of their enclosing types. I know it's a bit restrictive, but hopefully it'll help...

Jon Skeet
I thought about that but it effectively moves these checks into the business object itself, which I'm trying to avoid.
User
@so-tester: You can still have the checks in the factory rather than the BusinessObject type.
Jon Skeet
+5  A: 

Apart from what Jon suggested, you could also either have the factory method (including the check) be a static method of BusinessObject in the first place. Then, have the constructor private, and everyone else will be forced to use the static method.

public class BusinessObject
{
  public static Create (string myProperty)
  {
    if (...)
      return new BusinessObject (myProperty);
    else
      return null;
  }
}

But the real question is - why do you have this requirement? Is it acceptable to move the factory or the factory method into the class?

Fabian Schmied
This is hardly a requirement. I just want to have a clean separation of business object and logic. Just as it is inappropriate to have these checks in pages' code-behind, I deem it inappropriate to have these checks in objects themselves. Well, maybe basic validation, but not really business rules.
User
+1  A: 

Yet another (lightweight) option is to make a static factory method in the BusinessObject class and keep the constructor private.

public class BusinessObject
{
 public static BusinessObject NewBusinessObject(string property)
 {
  return new BusinessObject();
 }

 private BusinessObject()
 {
 }
}
Dan C.
+5  A: 

Or, if you want to go really fancy, invert control: Have the class return the factory, and instrument the factory with a delegate that can create the class.

public class BusinessObject
{
  public static BusinessObjectFactory GetFactory()
  {
    return new BusinessObjectFactory (p => return new BusinessObject (p));
  }

  private BusinessObject(string property)
  {
  }
}

public class BusinessObjectFactory
{
  private Func<string, BusinessObject> _ctorCaller;

  public BusinessObjectFactory (Func<string, BusinessObject> ctorCaller)
  {
    _ctorCaller = ctorCaller;
  }

  public BusinessObject CreateBusinessObject(string myProperty)
  {
    if (...)
      return _ctorCaller (myProperty);
    else
      return null;
  }
}

:)

Fabian Schmied
Wow, that one is good. I like it. But it's a really unusual one.
User
+1  A: 

So, it looks like what I want cannot be done in a "pure" way. It's always some kind of "call back" to the logic class.

Maybe I could do it in a simple way, just make a contructor method in the object class first call the logic class to check the input?

public MyBusinessObjectClass
{
    public string MyProperty { get; private set; }

    private MyBusinessObjectClass (string myProperty)
    {
        MyProperty  = myProperty;
    }

    pubilc static MyBusinessObjectClass CreateInstance (string myProperty)
    {
        if (MyBusinessLogicClass.ValidateBusinessObject (myProperty)) return new MyBusinessObjectClass (myProperty);

        return null;
    }
}

public MyBusinessLogicClass
{
    public static bool ValidateBusinessObject (string myProperty)
    {
        // Perform some check on myProperty

        return CheckResult;
    }
}

This way, the business object is not creatable directly and the public check method in business logic will do no harm either.

User
+1  A: 

I don't understand why you want to separate the "business logic" from the "business object". This sounds like a distortion of object orientation, and you'll end up tying yourself in knots by taking that approach.

Jim Arnold
I don't understand this distinction either. Can someone explain why this is being done, and what code would be in the business object?
pipTheGeek
It's just one approach that could be used. I want business object to be mainly data structures but not with all the field open for read/write.But the question really was about being able to instantiate an object only with the help of a factory method and not directly.
User
A: 

I'd put the factory in the same assembly as the domain class, and mark the domain class's constructor internal. This way any class in your domain may be able to create an instance, but you trust yourself not to, right? Anyone writing code outside of the domain layer will have to use your factory.

public class Person
{
  internal Person()
  {
  }
}

public class PersonFactory
{
  public Person Create()
  {
    return new Person();
  }  
}

However, I must question your approach :-)

I think that if you want your Person class to be valid upon creation you must put the code in the constructor.

public class Person
{
  public Person(string firstName, string lastName)
  {
    FirstName = firstName;
    LastName = lastName;
    Validate();
  }
}
Peter Morris
+5  A: 

Looks like you just want to run some business logic before creating the object - so why dont you just create a static method inside the "BusinessClass" that does all the dirty "myProperty" checking work, and make the constructor private?

public BusinessClass
{
    public string MyProperty { get; private set; }

    private BusinessClass()
    {
    }

    private BusinessClass(string myProperty)
    {
        MyProperty = myProperty;
    }

    public static BusinessClass CreateObject(string myProperty)
    {
        // Perform some check on myProperty

        if (/* all ok */)
            return new BusinessClass(myProperty);

        return null;
    }
}

Calling it would be pretty straightforward:

BusinessClass objBusiness = BusinessClass.CreateObject(someProperty);
Ricardo Nolde