Restrict instatiating of objects to interface types?

  • Thread starter Thread starter roland
  • Start date Start date
R

roland

All properties and methods of a class are implementations of two (or more)
interfaces.
Is it possible to enforce that only instances of the class can be
instantiated if they are already declared as one of those interfaces?

public class1
implements interface1,interface1
....
end class

should work:
dim A as interface1 = new class1
dim B as interface2 = new class1

should not work:
dim C as new class1
or
dim C as class1 = new class1


Tia, Roland
 
Hi Tia,

You can adopt the Factory pattern in this case. Make the constructor private
and expose a shared method that returns an instance of the instance type.
Here's what I mean:

Interface Itf1
Sub A()
End Interface

Class Class1
implements Itf1

private sub new()
...
end sub

Sub A() Implements Itf1.A
....
End Sub

public shared function GetInstance() As Itf1
return new Class1()
End function

End class


Sub Main()
Dim c As Itf1 = Class1.GetInstance()
c.A()
End Sub
 
You can still declare a variable of type class1 and instantiate it:

' with option strict off
dim oclass1 as class1 = class1.GetInstance()

' with option strict on
dim oclass1 as class1 = DirectCast(class1.GetInstance(), class1)

IMO, I think what the OP is asking is not possible. Whether one creates an
instance publicly or privately, one is always creating an instance of a
type - which in this case is class1 - and hence you can always declare a
variable of type class1 and instantiate it (via the constructor or a shared
method) even if it is only returning an interface type that the class
implements. Or is there something that I'm missing ??

Imran.

Manoj G said:
Hi Tia,

You can adopt the Factory pattern in this case. Make the constructor private
and expose a shared method that returns an instance of the instance type.
Here's what I mean:

Interface Itf1
Sub A()
End Interface

Class Class1
implements Itf1

private sub new()
..
end sub

Sub A() Implements Itf1.A
...
End Sub

public shared function GetInstance() As Itf1
return new Class1()
End function

End class


Sub Main()
Dim c As Itf1 = Class1.GetInstance()
c.A()
End Sub


--
HTH,
Manoj G
[MVP , Visual Developer - Visual Basic ]
http://msmvps.com/manoj/



roland said:
All properties and methods of a class are implementations of two (or more)
interfaces.
Is it possible to enforce that only instances of the class can be
instantiated if they are already declared as one of those interfaces?

public class1
implements interface1,interface1
...
end class

should work:
dim A as interface1 = new class1
dim B as interface2 = new class1

should not work:
dim C as new class1
or
dim C as class1 = new class1


Tia, Roland
 
Thanks for replying.
Imran is right. I took your code and checked it in the IDE. It provides for
the function, but you can bypass it easily by declaring a variable of
Class1 and cast or convert the instantiation to Class1.
dim t as Class1 = Ctype(Class1.Getinstance(),Class1)
or Dim t as Clas1=DirectCast(Class1.GetInstance(),class1)
I am a little bit surprised, because if you are putting
dim t as Interface1 = Class1.Getinstance()
you only have access to the interface1 methods and properties, and by
casting it, you actually can expand its scope, having access to all members
of the classs.
What I am looking foris a way to enforce my class limiting itself to a
susbset of it members, and one of the possibilities I am investigating is
doing this by Interfaces...
Regards, Roland

Manoj G said:
Hi Tia,

You can adopt the Factory pattern in this case. Make the constructor private
and expose a shared method that returns an instance of the instance type.
Here's what I mean:

Interface Itf1
Sub A()
End Interface

Class Class1
implements Itf1

private sub new()
..
end sub

Sub A() Implements Itf1.A
...
End Sub

public shared function GetInstance() As Itf1
return new Class1()
End function

End class


Sub Main()
Dim c As Itf1 = Class1.GetInstance()
c.A()
End Sub


--
HTH,
Manoj G
[MVP , Visual Developer - Visual Basic ]
http://msmvps.com/manoj/



roland said:
All properties and methods of a class are implementations of two (or more)
interfaces.
Is it possible to enforce that only instances of the class can be
instantiated if they are already declared as one of those interfaces?

public class1
implements interface1,interface1
...
end class

should work:
dim A as interface1 = new class1
dim B as interface2 = new class1

should not work:
dim C as new class1
or
dim C as class1 = new class1


Tia, Roland
 
roland said:
Thanks for replying.
Imran is right. I took your code and checked it in the IDE. It provides for
the function, but you can bypass it easily by declaring a variable of
Class1 and cast or convert the instantiation to Class1.
dim t as Class1 = Ctype(Class1.Getinstance(),Class1)
or Dim t as Clas1=DirectCast(Class1.GetInstance(),class1)
I am a little bit surprised, because if you are putting
dim t as Interface1 = Class1.Getinstance()

There's nothing surprising here. The object is of type class1 - so you
already have the entire object. If you're accessing the object via an
interface variable simply means you're only interested in the interface
members - the other members (if any) still exist and can always be accessed
via a variable declared as the object type (in our case of type class1).
you only have access to the interface1 methods and properties, and by
casting it, you actually can expand its scope, having access to all members
of the classs.
What I am looking foris a way to enforce my class limiting itself to a
susbset of it members, and one of the possibilities I am investigating is
doing this by Interfaces...

I'm not exactly sure what the purpose is but here's just an idea:
You can make all the implemented members in your class as private. Now, if
you want to access any of the interface members, you'll always have to cast
it to that interface - you'll not be able to access them directly via the
class1 object. You surely cannot prevent anyone from accessing the other
members in anyway (unless you make them private!).

hope that helps..
Imran.
 
Thanks for your comments, Imran.
What I want to achieve is to build assembly which I can "publish" as a
"demo" that is only providing a subset of its abilities (methods,
properties) and is providing the full monty when a license is available
(both at design time). As such the class(es) should have a way to 'hide'
some members.
I am currently investigating whether the use of interfaces is the right
path...
I will make a prototype with this idea of yours, maybe it triggers some
further ideas.
Regards, Roland
 
Imran
I checked your proposal to make the implementations of the interfaces
private in the class. It is true that no variable pointing to an object of
class1 can access those members but that interface variables pointing to
such objects do. I do understand some of the logic: after all, the interface
declares a number of methods/properties that have to be implemented by the
class that implements the interface and as such, those methods should be
accesible, but on the other hand, the variable is pointing to an object of
this class and as such the object has to adhere to the rules of the class
(private/public/friend) or are both facets additive rather than restrictive?
If that is true, why can such a variable only access the class members that
are implementations of the interface they are pointing to (which is
restrictive)?
Anyway, the concept of making the members private is worth expanding.
Regards, Roland
 
Hi Roland,

I finally understand the problem.

May I suggest an entirely different tactic.

Have a factory method return an object that meets InterfaceA
Define only one interface.

If the license has been granted, then the factory method will return a fully
functional object.
If the license has not been granted, then the factory method will return an
object with some members returning an Exception NOT_IMPLEMENTED

Not only is it similar, but it makes marketing sense. Your user will know
that they control or component has a "full" version and a "demo" version.
You WANT them to know that, and you WANT them to see that there is *really
useful code* in the full version that is not implemented in the demo
version.

So, in the documentation, let them know what each call will do for them, and
also let them know which calls are only for the full version.

If they use a full-version component in an app where they have not purchased
the licesne, they get an exception thrown. (At that point, they call up
your web site and pony-up the cash).

That's how I'd do it, anyway.

Good luck,
--- Nick
 
Nick
You are the second person who makes this suggestion and I start to believe
that it's the only way which is easy to implement. The reason why I declined
the suggestion of the first person (Christopher Kimbell) was that I wanted
more "subtle" way to deal with this problem (no Exceptions thrown).
I believe that I can abandon the factory method altogether:
..Components need a default construction method (New)
..At the first instantiation of an object, the class is searching for a valid
license which is put in a class (shared) variable.
..The methods that I don't want to implement in the demo are checking the
value of this shared variable, if eq. nothing, an exception is thrown,
making the binding with the object impossible. This I should check, to make
sure that no late binding is possible, which would circumvent the whole
setup (I would prefer to use only a design-time license).
Any comments?
Regards, Roland
 
roland said:
Imran
I checked your proposal to make the implementations of the interfaces
private in the class. It is true that no variable pointing to an object of
class1 can access those members but that interface variables pointing to
such objects do. I do understand some of the logic: after all, the
interface
declares a number of methods/properties that have to be implemented by the
class that implements the interface and as such, those methods should be
accesible, but on the other hand, the variable is pointing to an object of
this class and as such the object has to adhere to the rules of the class
(private/public/friend) or are both facets additive rather than
restrictive?

Roland,

As you know, an interface cannot have access modifiers for its members. So
the only applicable access modifiers for the members when defined in a class
implementing this interface are the ones that you use in the class. If the
members are declared private, then you won't be able to access those members
directly - you would either use a variable of the interface type or simply
cast the object to the interface type and access those members.
If that is true, why can such a variable only access the class members
that
are implementations of the interface they are pointing to (which is
restrictive)?

That's how interfaces have been implemented always. Earlier in VB6,
interface members were private only. You didnt have the option of making
them public. As a result, the only way to access members of the interface
implemented by a class was via a variabe declared as the interface type or
by casting the object to the interface type. Its only in .NET that one has
the option to change the access modifiers of interface members.

hope that helps..
Imran.
 
Hi Roland,

Methods don't have constructors. Classes do. If the class has even one
method that needs to be available in both demo and full versions, you can't
fire an exception during it's constructor, or the user won't be able to get
to your demo methods.

Also, the method of using a factory object has one other advantage: you
could decide (at any time, at your discretion) to change your strategy
completely and ship two different objects, one compiled with directives that
literally omit the functioning code (thus preventing disassembly-tampering)
and the other, where you deliver two objects: the demo version and the full
version where the full version simply uses the same interface, inherits from
the demo version and overrides the methods that are disabled (thus making it
much smaller). You could actually deliver the final code in the same
download where you provide the license.

If you directly use New, you would lose backwards compatibility if you
decide to go with this more secure method in version 2.

Also, from a pure language and patterns perspective, avoiding 'New' has its
advantages.
See this article: http://java.ittoolbox.com/documents/document.asp?i=1735
while the topic is Java, the criticism of the 'new' keyword would be
IDENTICAL for C# or VB.NET.

Good Luck,
--- Nick
 
Nick
I read my mail again to understand why you stated
"Methods don't have constructors. Classes do".
Maybe I didn't express my self concisely: what I wanted to say is that
factory methods (although they are more flexible) are not always useable:
for instance with controls that you can drag from the toolbox and drop on a
form. The code generated in the designer to instantiate the control is x =
new [class]. So AFAIK, the class needs to expose the default constructor.
With experimenting I found out that throwing an exception in an instance
method at design time if there is no design time license (as I stated in my
mail) is worthless, if the code is not executed at that time.It will compile
happily and if there is no runtime license, the demo version will do the
same thing as the full version.
So, I believe I have to fold back on the following approach:
- Make a full implementation of the control/component.
- Build in a check for a design time license in the constructor and throw an
exception if there is no valid license, preventing to instantiate the
control altogether (and hopefully to compile the source code in any other
way, this I have to check)
- Have compiler directives in the source above that allow me to build a
trimmed down demo version that does not need a license.
- Publish the latter freely for demo purpose
- Deliver the full version plus license to customers.
Probably this solution is more robust than all those fancy tricks, because
the demo component is not containing the code that the licensed version has
(as you stated).
Regards, Roland
 
Imran
Thanks. I actually never used interfaces in VB6. In .Net I am using them as
merely a design tool. It's only when I started looking at the possibility
for giving classes a more dynamic behaviour, that I took a closer look.
Regards, Roland
 
roland said:
Nick
I read my mail again to understand why you stated
"Methods don't have constructors. Classes do".
Maybe I didn't express my self concisely: what I wanted to say is that
factory methods (although they are more flexible) are not always useable:
for instance with controls that you can drag from the toolbox and drop on
a
form. The code generated in the designer to instantiate the control is x =
new [class]. So AFAIK, the class needs to expose the default constructor.

Roland, you might look into creating a TypeConverter which can convert from
your type to an instance descriptor. When such a TypeConverter exists, the
designer uses it to figure out how to instantiate an object of your type. I
know that such a TypeConverter gets to choose which constructor to use.
Perhaps it also could cause a factory method to be used.

John Saunders
 
Thanks John, I didn't know that.
On the other hand, I am not to keen on Typeconverters: currently I am
investigating a typeconverter bug in the vbPowerpack (Blendfill) and I am
gazing at a casting error, although the object is of the right type and its
variables are well initialised.
Regards, Roland

John Saunders said:
roland said:
Nick
I read my mail again to understand why you stated
"Methods don't have constructors. Classes do".
Maybe I didn't express my self concisely: what I wanted to say is that
factory methods (although they are more flexible) are not always useable:
for instance with controls that you can drag from the toolbox and drop on
a
form. The code generated in the designer to instantiate the control is x =
new [class]. So AFAIK, the class needs to expose the default
constructor.

Roland, you might look into creating a TypeConverter which can convert from
your type to an instance descriptor. When such a TypeConverter exists, the
designer uses it to figure out how to instantiate an object of your type. I
know that such a TypeConverter gets to choose which constructor to use.
Perhaps it also could cause a factory method to be used.

John Saunders
 
Back
Top