By definition, a smart proxy object must inherit the same interface as the real object it represents and should reside in the client process's address space to provide the best possible performance to the client. In that regard, a smart proxy class intended for reuse with different clients must be packaged in an ActiveX DLL component. (DLLs load in the client process's address space.) To implement the interface of the real object, the ActiveX DLL in which the smart proxy class is defined must reference the same type library that defines the interface implemented by the class that defines the real object.
In general, you don't need to make the client aware of whether it is referencing the smart proxy object or the real object. Providing this level of transparency can be the most challenging aspect of the design, but it will allow you to take advantage of the benefits (listed in the "Utilization" section of this chapter) without disruption to the client code. Providing this level of transparency will require the removal of explicit object creation from the client code.
Figure 7-2. The object factory adds local/remote transparency to the client code by determining that the object requested by the client can be created in the client's address space.
Implementing an Object Factory design pattern (Chapter 8) within the ActiveX DLL that defines the smart proxy is a suitable alternative to using the keyword New or the CreateObject function. The object factory can easily address the local/remote transparency issue by determining whether the object requested by the client can be constructed in the client's address space. If so, the object factory creates an instance of the real object and then returns a direct reference to the client. (See Figure 7-2.) Otherwise, the object factory creates an instance of the real object running in a separate process (ActiveX EXE), at which point COM will interpose and return a dumb proxy of the real object. The object factory then will create a smart proxy that maintains a reference to the dumb proxy created by COM. A direct reference to the smart proxy is returned to the client. (See Figure 7-3.) Eventually, all requests intended for the real object will be submitted by the smart proxy via the COM dumb proxy.
Figure 7-3. The object factory adds local/remote transparency to the client code by determining that the object requested by the client must be created in the address space of another process.
Smart proxies can also serve as security guards for the real object by regulating access to the real object's properties and methods. Using an object factory will make the introduction of secured access to the real object nonintrusive to the client application. You cannot enforce security, however, if the client is permitted to create an instance of the real object by employing conventional language features (such as the keyword New or the CreateObject function). To enforce security, follow these steps:
The client code that accesses the smart proxy and object factory combination can be as simple as the following code extract.
' Because the PersonFactory abstracts the explicit creation, it is ' not difficult to imagine that the PersonFactory could be enhanced ' to return a SmartProxyPerson instead of a RealPerson object ' without modification to the following client code. Dim personFact As PersonFactory Dim person1 As Person ' Create PersonFactory. Set personFact = New PersonFactory ' PersonFactory creates an object that supports the Person ' interface expected by the client. The client is oblivious ' to whether the object is the real person or the smart proxy. Set person1 = personFact.CreatePerson() |
WARNING
Be extremely cautious when implementing public interfaces in private classes. Based on Visual Basic's implementation of COM, requests made through the public interface do not marshal across apartment boundaries, which include cross-thread and cross-process. Run-time errors will result. To avoid this scenario, make the private classes PublicNotCreatable. You can't prevent the client from being aware of the existence of these classes, but you can still prohibit the client from creating instances of them. This is not the ideal solution, but it is effective nonetheless. I suspect that someday this functionality in Visual Basic will be improved.