Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro .NET 2.0 Code And Design Standards In CSharp (2006) [eng]

.pdf
Скачиваний:
34
Добавлен:
16.08.2013
Размер:
3.43 Mб
Скачать

206 C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

Key Code Ingredients

The code for the Surrogate-Proxy pattern has the following key ingredients:

An interface type (IDesignEngineer).

A principal class (ChiefDesignEngineer) that implements IDesignEngineer interface.

A proxy class (ProxyChiefDesignEngineer) that also implements the IDesignEngineer interface, which

has a member instance of the principal class (ChiefDesignEngineer).

implements the methods inherited from IDesignEngineer that wrap the methods of the member instance of the principal class (ChiefDesignEngineer) and further specializes two of them (PerformanceKnowledge() and MechanicalKnowledge()).

Client code that instantiates the proxy class (ProxyChiefDesignEngineer), then calls the methods of the ProxyChiefDesignEngineer class.

Now let’s code the Surrogate-Proxy pattern.

Surrogate-Proxy Pattern Code

The essence of the design lies in the way that a proxy class (ProxyChiefDesignEngineer) selects composition or containment rather than inheritance to regulate access to the functionality of the principal (ChiefDesignEngineer). Notice that the IDesignEngineer interface type provides the interface, which is inherited and implemented by ChiefDesignEngineer and

ProxyChiefDesignerEngineer classes. The proxy class (ProxyChiefDesignEngineer) wraps the methods of the principal class (ProxyChiefDesignEngineer), except where it wants to shield the principal from the nonadvanced or run-of-the-mill questions, in which case it provides its own implementation (see PerformanceKnowledge() and MechanicalKnowledge() methods).

DesignEngineer Interface

public interface IDesignEngineer

{

string DesignKnowledge(); string StressTestKnowledge(); string MechanicalKnowledge(); string PerformanceKnowledge();

}

ChiefDesignEngineer Class

public class ChiefDesignEngineer: IDesignEngineer

{

public string DesignKnowledge()

{

return "The Model T is designed to...";

C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

207

}

public string StressTestKnowledge()

{

return "We found in stress-testing, the...";

}

public string MechanicalKnowledge()

{

return "The mechanical features include...";

}

public string PerformanceKnowledge()

{

return "The performance characteristics include...";

}

public ChiefDesignEngineer() {;}

}

ProxyChiefDesignEngineer Class

public class ProxyChiefDesignEngineer: IDesignEngineer

{

private ChiefDesignEngineer chief;

public string DesignKnowledge()

{

return this.chief.DesignKnowledge();

}

public string StressTestKnowledge()

{

return this. chief.StressTestKnowledge();

}

//The proxy can also be used to save "over-use" of the principal, //by encapsulating a means to handle queries internally.

public string MechanicalKnowledge()

{

return "A supplement has been added to the mechanical manual.";

public string PerformanceKnowledge()

{

return "Performance information is in the manual.";

}

208 C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

//constructor - instantiates local copy of ChiefDesignEngineer. public ProxyChiefDesignEngineer()

{

this.chief = new ChiefDesignEngineer();

}

}

Client Code

In the client code, we can see the Surrogate-Proxy design pattern at work. We test the effectiveness of the design pattern by instructing the client code to deal directly through two proxies of the principal (caProxyChief and nyProxyChief). Although the client has access to the principal, it does so through the proxies, which act as surrogates for the principal (ChiefDesignEngineer).

public class Client

{

static void Main(string[] args)

{

//Create a proxy ChiefDesignEngineer

//to handle Californian State technical queries ProxyChiefDesignEngineer caProxyChief =

new ProxyChiefDesignEngineer();

//Setup the console

Console.WriteLine("*** Answer(s) for CA State ***");

//Ask a stress-test question of the ProxyChief Console.WriteLine(caProxyChief.StressTestKnowledge());

//Ask a performance question of the ProxyChief Console.WriteLine(caProxyChief.PerformanceKnowledge());

//Create a proxy ChiefDesignEngineer

//to handle NewYork State technical queries ProxyChiefDesignEngineer nyProxyChief =

new ProxyChiefDesignEngineer();

//Setup console Console.WriteLine();

Console.WriteLine("*** Answer(s) for NY State ***");

//Ask a mechnical question of the ProxyChief Console.WriteLine(nyProxyChief.MechanicalKnowledge());

}

}

C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

209

Console Output

*** Answer(s) for CA State ***

We found in stress-testing, the . . .

Performance information is in the manual.

*** Answer(s) for NY State ***

A supplement has been added to the mechnical manual. Press any key to continue

The Standard: Surrogate-Proxy Design Pattern

The standard acknowledges the use of the Surrogate-Proxy design pattern where there is a design problem such that access to a principal (e.g., scarce resource) needs to be regulated.

Pattern Example: Remote-Proxy

In the Model T domain, the policy of allowing workshop managers to ask advanced questions of the chief design engineer has been so successful that the policy is to be extended, for a limited time, to major dealers in the United Kingdom (UK). We have been asked to do the wiring.

The part of the problem we are focusing on is how to extend access to the remote UK workshop managers so they can channel their queries in a systematic manner to the chief design engineer and receive the answers. The solution requires implementing an architecture that relies on TCP transport protocol and .NET Remoting. The following code example extends the business case introduced in the Surrogate-Proxy example, although it is a self-contained example. We will reuse IDesignEngineer, which is inherited by ChiefDesignEngineer and ProxyChiefDesignEngineer; however, we also make the two classes inherit from the MarshallByRef class, so that they can be transported using TCP. The multiple inheritance is not a problem: .NET permits single class inheritance to be combined with (multiple) interface inheritance.

Note In Appendix A, there is a step-by-step example on setting up this pattern using the command line. Preferably, you may continue to read through this discussion, get an overview of the pattern, and then go to the appendix and set up the example. (Use the download code or key in the code, as there are respective code listings following.) Also, to do the example you will need to know a little bit about environment variables and command-line programming—primers can be found in Appendix A, if you need them (see “Environment Variables” and “Remote-Proxy Pattern Example—Using the Command Line”).

210 C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

Architecture

This pattern has a server and a remote client, which reside in separate domains and are connected using transport protocol (TCP). The following diagram (Figure 11-2) illustrates the architecture. Note that both domains have a local copy of RemoteProxyServer.dll and access to .NET Remoting (from the .NET Framework).

Figure 11-2. Remote-Proxy architecture

Code

We code two sets of functionality (server and client), and both sets will have access, within their respective domains, to a copy of the same class library (ProxyRemoteServer.dll), that defines the actors (e.g., ProxyChiefDesignEngineer). The client needs a local copy of the class library so that it can create an association with the ProxyChiefDesignEngineer. Let’s now examine each of the new classes in turn.

ProxyRemoteServer.cs

This class plays the role of an “interface” class; it is through this class that the client will interface with the ChiefDesignEngineer. (This class will eventually be compiled into a class library file—ProxyRemoteServer.dll.)

Server.cs

ProxyRemoteServer is an “interface” class, whereas the Server class fulfils the role of a server “plumber” class: it encapsulates all of the functionality to create a TCP Server Channel. In the code, use is made of port 1234; this number is chosen because it is a Well Known Port. The

.NET Remoting configuration is used to register a Well Known Service and it is passed the name of the proxy class (ProxyChiefDesignerEngineer), a service name (“RemoteProxy”), and uses the SingleCall option of the Well Known Object Mode. The code writes a message to the console and stays open waiting for a call from the client application (which is discussed next).

C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

211

Client.cs

The Client class plays two roles: it acts as a client “plumber” class, mirroring the role of Server, and it also fires off questions to the ProxyChiefDesignerEngineer. We register a TCP channel with .NET channel services, and then we configure .NET’s remoting to register use of the RegisterWellKnownClientType configuration option. .NET’s remoting configuration is passed the type of proxy object (ProxyChiefDesignerEngineer) and the address of the service (tcp://localhost:1234/RemoteProxy). If we were to use this service outside of the example environment, then we would modify the localhost setting.

Having made connection through the transport protocol, the code then instantiates a local proxy instance of the ProxyChiefDesignEngineer class, through which .NET Remoting calls on the ProxyChiefDesignEngineer object, located on the remote server, to call the methods of the ChiefDesignEngineer object (also located on the remote server). The response is seen on the client console. We shall now look at the Remote-Proxy pattern in a UML diagram (see Figure 11-3) and then discuss the code.

UML

Figure 11-3. Remote-Proxy pattern

212 C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

Key Code Ingredients

The code for the Remote-Proxy pattern has the following key ingredients:

An interface type (IDesignEngineer).

A principal class (ChiefDesignEngineer) that inherits from MarshalByRefObject class, so that it can be transported across a domain, and that implements IDesignEngineer interface.

A proxy class (ProxyChiefDesignEngineer) that inherits from MarshalByRefObject class, so that it can be transported across a domain, and that implements the IDesignEngineer interface.

A member instance of the principal class (ChiefDesignEngineer).

Implements the methods inherited from IDesignEngineer, which wrap the methods of the member instance of the principal class (ChiefDesignEngineer), and further specializes two of them (PerformanceKnowledge() and MechanicalKnowledge()).

Server code (Server.cs) that handles the transport plumbing, from the server perspective.

Client code (Client.cs) that handles the transport plumbing, from the client perspective; instantiates a local proxy class (ProxyChiefDesignEngineer), and through this interface calls the methods of the remote ProxyChiefDesignEngineer class (which is located on the server).

Now let’s code the Remote-Proxy pattern.

Remote-Proxy Pattern Code

The essence of the design lies in the way that an instance of class (ProxyChiefDesignEngineer), which is resident on the server, is marshaled by reference by .NET Remoting using TCP transport and a remote proxy interface (ProxyChiefDesignEngineer), located on the client, through which the client (Client.exe) accesses the remote functionality. Behind the scenes, .NET Remoting manages transporting the functionality via a TCP port (port 1234 on the localhost), shielding us from that complexity.

ProxyRemoteServer Class

The ProxyRemoteServer class is a container class that stores the interface type and classes:

IDesignEngineer, ChiefDesignEngineer, and ProxyChiefDesignEngineer. The ProxyRemoteServer class will be complied into a class library (ProxyRemoteServer.dll).

DesignEngineer Interface

public interface IDesignEngineer

{

string DesignKnowledge(); string StressTestKnowledge(); string MechanicalKnowledge();

C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

213

ChiefDesignEngineer Class

public class ChiefDesignEngineer: MarshalByRefObject, IDesignEngineer

{

public string DesignKnowledge()

{

return "The Model T is designed to...";

}

public string StressTestKnowledge()

{

return "We found in stress-testing, the...";

}

public string MechanicalKnowledge()

{

return "The mechanical features include...";

}

public string PerformanceKnowledge()

{

return "The performance characteristics include...";

}

public ChiefDesignEngineer() {;}

}

ProxyChiefDesignEngineer Class

public class ProxyChiefDesignEngineer: MarshalByRefObject, IDesignEngineer

{

private ChiefDesignEngineer chief;

public string DesignKnowledge()

{

return this.chief.DesignKnowledge();

}

public string StressTestKnowledge()

{

return this.chief.StressTestKnowledge();

}

//The proxy can also be used to save "over-use" of the principal, //by encapsulating a means to handle queries internally.

public string MechanicalKnowledge()

214 C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

{

return "A supplement has been added to the mechanical manual.";

}

public string PerformanceKnowledge()

{

return "Performance information is in the manual.";

}

//constructor - instantiates local copy of ChiefDesignEngineer. public ProxyChiefDesignEngineer()

{

this.chief = new ChiefDesignEngineer();

}

}

Here is the complete code listing of ProxyRemoteServer.cs, which will be compiled into ProxyRemoteServer.dll:

using System;

namespace Patterns.ProxyRemoteServer

{

public interface IDesignEngineer

{

string DesignKnowledge(); string StressTestKnowledge(); string MechanicalKnowledge(); string PerformanceKnowledge();

}

public class ChiefDesignEngineer: MarshalByRefObject, IDesignEngineer

{

public string DesignKnowledge()

{

return "The Model T is designed to...";

}

public string StressTestKnowledge()

{

return "We found in stress-testing, the...";

}

public string MechanicalKnowledge()

{

return "The mechanical features include...";

}

C H A P T E R 1 1 S T R U C T U R A L PAT T E R N S

215

public string PerformanceKnowledge()

{

return "The performance characteristics include...";

}

public ChiefDesignEngineer() {;}

}

public class ProxyChiefDesignEngineer: MarshalByRefObject, IDesignEngineer

{

private ChiefDesignEngineer chief;

public string DesignKnowledge()

{

return this.chief.DesignKnowledge();

}

public string StressTestKnowledge()

{

return this.chief.StressTestKnowledge();

}

//The proxy can also be used to save "over-use" of the principal, //by encapsulating a means to handle queries internally.

public string MechanicalKnowledge()

{

return "A supplement has been added to the mechanical manual.";

}

public string PerformanceKnowledge()

{

return "Performance information is in the manual.";

}

//constructor - instantiates local copy of ChiefDesignEngineer. public ProxyChiefDesignEngineer()

{

this.chief = new ChiefDesignEngineer();

}

}

}// end namespace

Соседние файлы в предмете Программирование на C++