How to control access to inner class through outer class

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Consider the following class layout

public class Order
{
public ProductOrder AddProductOrder(/* variables required to create a
product order */)
{
/* Check if the product order can be added to the order */
}

public class ProductOrder
{
// This cant be private if i want to use it from the encapsulating
class!
private ProductOrder(/**/)
{
}
}
}

The idea is to control access to the inner class, because the inner class
can not exist without the outer class, but i can't make the ctor private
because it''s not visible from the encapsulating class. If anyone can solve
the above without exposing the ctor of the inner class outside of the wrapped
class I would like to hear from you. Also, if you know some great sites or
books which discuss design patterns which are relevant to business logic,
please point me in the right direction :-)
 
MariusI said:
Consider the following class layout

public class Order
{
public ProductOrder AddProductOrder(/* variables required to
create a product order */)
{
/* Check if the product order can be added to the order */
}

public class ProductOrder
{
// This cant be private if i want to use it from the
encapsulating class!
private ProductOrder(/**/)
{
}
}
}

The idea is to control access to the inner class, because the inner
class can not exist without the outer class, but i can't make the
ctor private because it''s not visible from the encapsulating class.
If anyone can solve the above without exposing the ctor of the inner
class outside of the wrapped class I would like to hear from you.
Also, if you know some great sites or books which discuss design
patterns which are relevant to business logic, please point me in the
right direction :-)

Don't use inner classes if you're exposing the type to the outside of
the containing class. So you're exposing ProductOrder to the outside of
Order, which thus means the code outside Order knows what a
ProductOrder is, so the location of ProductOrder doesn't matter so
place it outside Order.

As ProductOrder has to rely on an Order, you can construct the
Productorder's constructor in such a way that it accepts an Order
object (and not null) and only in the constructor, not via a set
property. This way you can't create a ProductOrder without an instance
of its Order.

Though what's the relation between order and productorder? it SOUNDS
like a subtype...

FB

--
 
An order can contain one or more productOrders. A productOrder specifies a
product and how many entities you want to place an order on. There are design
patterns which expose inner classes to outside code, such as the
IEnumerable/IEnumerator pattern. The main reason for using a factory method
insted of a ctor in the ProductOrder class, is that the business rules which
controls creation of producOrders are highly dependent on the Order class. I
could of course, access the encapsulating class through the inner class, but
i wanted to apply the business logic in the class which controls it. The
outer/inner class pattern was chosen to emphasise that the innerclass is not
relevant outside of an order context and should be read-only exposed outside
of the class.
 
MariusI said:
Consider the following class layout

public class Order
{
public ProductOrder AddProductOrder(/* variables required to create a
product order */)
{
/* Check if the product order can be added to the order */
}

public class ProductOrder
{
// This cant be private if i want to use it from the encapsulating
class!
private ProductOrder(/**/)
{
}
}
}

The idea is to control access to the inner class, because the inner class
can not exist without the outer class, but i can't make the ctor private
because it''s not visible from the encapsulating class. If anyone can
solve
the above without exposing the ctor of the inner class outside of the
wrapped
class I would like to hear from you. Also, if you know some great sites or
books which discuss design patterns which are relevant to business logic,
please point me in the right direction :-)

The usual way to do this is using "internal" access.

Obviously this is not totally satisfactory because it would only prevent
code from outside your assembly from creating the class but this is the
method that the framework uses and it allows you to unnest the class which
is logically wrong but makes for much less messy code.

Where are your C++ friends when you need them? :-)
 
The internal modifier is not satisfactory for my needs. Yes, i get to hide my
implementation between dll's, but that's not enough considering i have a
large dll with both consumer/producer classes and that means that the
consumer classes still have access.
 
MariusI said:
An order can contain one or more productOrders. A productOrder
specifies a product and how many entities you want to place an order
on. There are design patterns which expose inner classes to outside
code, such as the IEnumerable/IEnumerator pattern. The main reason
for using a factory method insted of a ctor in the ProductOrder
class, is that the business rules which controls creation of
producOrders are highly dependent on the Order class. I could of
course, access the encapsulating class through the inner class, but i
wanted to apply the business logic in the class which controls it.
The outer/inner class pattern was chosen to emphasise that the
innerclass is not relevant outside of an order context and should be
read-only exposed outside of the class.

All nice and dandy, but if you have an INNER class ProductOrder,
inside Order, it's normally not meant to be used as: (core outside
Order)
ProductOrder p = myOrder.AddProductOrder(...);

Because that suggests that the type ProductOrder is known outside the
scope of Order. If that's the case, place ProductOrder as type outside
Order.

Your suggestion that it's a design pattern isn't applicable for this
situation, because you then should use an interface which is known
outside the scope of Order, which is implemented by ProductOrder:
IFoo p = myOrder.AddProductOrder(...);

p has type IFoo (just for illustrational purposes, I cooked up this
name, but you get the idea) but is actually a ProductOrder object, but
you don't know that, nor should you care as you're working outside the
scope of Order and thus also in territory where 'ProductOrder' as a
type shouldn't be known.

If you then define ProductOrder private, you can't create an instance
of ProductOrder outside Order, however you can use it outside
ProductOrder, as you refer to it through the interface.

FB



--
 
Typed DataSets provide the exact same behaviour as the one i'm implementing.
Typed DataTables are implemented as inner classes of the typed dataset and
they can only be accessed through factory methods in the outer class (typed
dataset).
 
Mariusl,

I see where you're coming from. But I see Frans' point too. Let me
tell you what the Framework Design Guidelines book from the Microsoft
Development Series has to say about this.

"Avoid publicly exposed nested types. The only exception to this is if
variables of the nested type need to be declared only in rare scenarios
such as subclassing or other advanced customization scenarios."

Personally, I don't think your case fits the exception because callers
of your code would frequently declare the ProductOrder type so that
they have a place to land the reference returned by AddProductOrder.

Here's an example that I think does fit the exception.

public class Order
{
private ProductOrderCollection productOrders = new
ProductOrderCollection();

public ProductOrderCollection ProductOrders
{
get { return productOrders; }
}

public ProductOrderCollection : CollectionBase
{
internal ProductOrderCollection()
{
}

public void Add(ProductOrder productOrder)
{
}
}
}

public class ProductOrder
{
}

In this example ProductOrderCollection is public (though not publicly
creatable), but it would rarely be declared by calling code. There is
absolutely nothing new you can do with a local reference to
ProductOrderCollection that you can't do by simply accessing it through
the Order class. Therefore, there is little benefit in callers
declaring their own reference.

Brian
 
Based on the guidelines i can see where you're critisism comes from. Thanks
for the Framework design guidelines tip. I'll dive into it right away,
looking for ways to standarize my code :-)
 
Mariusl,

Well, obviously Microsoft hasn't adhered to their own standards. You
mentioned that strongly typed datasets have public nested types. I
frequently declare references of those types so I don't think they fit
the exception either and yet Microsoft still choose to do it that way.

Brian
 
Back
Top