C# Coding Solutions—Nested Private-Class Bridge-Pattern Variation
Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio
Nested Private-Class Bridge-Pattern Variation
Another variation of the Bridge pattern is to make the implementations of the Bridge pattern a nested private class. There can be multiple private classes and private abstract classes. You are moving code that would normally be in a separate namespace into a class. The class controls all access to the embedded classes. Usually the class that contains the implementations is the Factory pattern implementation itself. The big idea behind this pattern is to implement the Adapter pattern in a focused context.
Imagine writing an application that has the task to manage sources of data. The application is an evolution and there is an already existing source code base. In this existing source code base there are interfaces and implementations. Your task is to rewrite the code to use the new interfaces. The Adapter pattern provides an excellent way of fitting an old functionality into a new interface. The problem is that fitting new functionality on old functionality is a messy business. Typically you will implement a host of tricks to make a square peg fit into a round hole. Those tricks result in working code, but that code may require reworking and refactoring. You don’t rewrite the base because it is still needed, and more importantly it works. At some later point in time you will rewrite, but not today.
The problem that you have with the new Adapter pattern code is that it works, but you would not be keen to have anybody else use the code. It is temporary code that will change at some later point in time. Using the private class variation of the Bridge pattern, all of the messy details stay in the context of the Factory used to instantiate the class. When implementing classes using this type of Factory, it is important to not write thousands of lines of code. The idea is to provide an adapter from an interface to another subsystem that has the already-working implementation.
The following example is a data source utility that reads a single byte from two data sources: file and ZIP file. The code used to implement the example is straightforward, but has some subtle details:
public interface IDataSource { char ReadByte(); } public interface IDataSourceFactory { IDataSource CreateZipDataSource(); IDataSource CreateFileDataSource(); } class DataSourceAdapterFactory : IDataSourceFactory { #region ZIP Implementation (ZipDataSourceImplementation) private class ZipDataSourceImplementation : IDataSource { public char ReadByte() { // Call external assembly return 0; } } #endregion public IDataSource CreateZipDataSource() { return new ZipDataSourceImplementation(); } #region File Implementation (FileDataSourceImplementation) private class FileDataSourceImplementation : IDataSource { public char ReadByte() { // Call external assembly return 0; } } #endregion public IDataSource CreateFileDataSource() { return new FileDataSourceImplementation(); } } public class DataSourceFactoryImplementation { public static IDataSourceFactory CreateFactory() { return new DataSourceAdapterFactory(); } }
The interface IDataSource represents a core definition that is used throughout the application. The interface IDataSourceFactory can be specific to the implementation of the private class Bridge pattern variation. I say can be specific because in some situations you would use an interface to implement a factory. For the context of the private class implementation, defining an interface for the factory is the most appropriate because the private class implementation is an Adapter pattern implementation that will eventually be reworked and replaced with another factory. The class DataSourceFactory implementation will not change method signatures, but the implementation of DataSourceFactoryImplementation.CreateFactory will change.
The class DataSourceAdapterFactory implements the IDataSourceFactory interface and instantiates the private class implementations of the interface IDataSource. The method CreateFileDataSource instantiates the type FileDataSourceImplementation, and the method CreateZipDataSource instantiates ZipDataSourceImplementation.
The class implementations FileDataSourceImplementation and ZipDataSourceImplementation contain comments to the calling of an external assembly. The class implementations are lightweight classes that provide enough code to wire a new interface to an old subsystem. Extensive logic should not be implemented in the private classes. If extensive logic is required, then consider that logic as a half step toward reworking the legacy code, and create an intermediary layer that will eventually replace the DataSourceAdapterFactory class.
One last detail when implementing the methods and private classes is that they are wrapped in #region and #endregion directives. Using the directives and Microsoft Visual Studio makes it possible to fold large regions of code, making it simpler to understand the overall perspective of the class implementation.
When working with the private class variation of the Bridge pattern, remember the following:
- Nested private classes allow the implementation of interfaces without exposing the classes to external manipulations such as instantiation or subclassing.
- When using nested private classes, typically you will be implementing the Adapter pattern that converts an old system to a new system.
- Generally nested private classes are temporary and subject to reworking and refactoring. The classes are defined as nested and private so that all code can be isolated to a single class.
- Use a nested private class for long-term class implementation if you want to combine many disparate systems and expose those systems using a single interface.
|

