Home > Articles > Programming > Windows Programming

This chapter is from the book

Rule 2-2: Use Custom Interfaces

COM is more than just a technology for building software—it is also a philosophy for building systems that evolve more easily over time. The designers of COM recognized that excessive coupling hinders evolution, and thus sought a mechanism that minimized the coupling between components. For example, VB clients typically reference a class directly:

Dim rEmp As CEmployee '** class-based reference = default interface

As we know from rule 2-1, this declaration implicitly couples the client code to the default interface of class CEmployee. Because an interface represents a binding contract between client and class, this coupling prevents the class from evolving. But what if you really need to make an interface change (e.g., to extend a class's functionality or to repair a design oversight)?

The COM solution is to embrace explicitly interfaces in both the clients and the classes—an approach known as interface-based programming. Instead of presenting a single default interface, classes now publicize one or more custom interfaces. Clients then decide which custom interface they need, and couple to this interface much like before. The key difference, however, is that classes are free to introduce new custom interfaces over time. This allows the class to evolve and to serve new clients, yet remain backward compatible with existing clients. Interface-based programming is thus a design technique in which interfaces serve as the layer of abstraction between clients and classes. As shown in Figure 2.2, this minimizes coupling on the class itself.

Figure 2.2 Two views of an interface

How do you define a custom interface? Like classes, custom interfaces are created in VB using class modules. Unlike classes, they contain no implementation because a custom interface is simply a set of method signatures. For example, here's the default interface of CEmployee (from rule 2-1) rewritten as a custom interface named IEmployee:

'** class module IEmployee
Option Explicit

Public Property Get Name() As String
End Sub

Public Property Get Salary() As Currency
End Sub

Public Sub ReadFromDB()
End Sub

Public Sub IssuePaycheck()
End Sub

Note the absence of implementation details (i.e., private members and code). A custom interface thus represents an abstract class, which is conveyed in VB by setting the class's Instancing property to PublicNotCreatable. This also prevents clients from mistakenly trying to instantiate your interfaces at run-time.

Once defined, custom interfaces must be implemented in one or more class modules. For example, here is the class CConsultant that implements our custom interface IEmployee:

'** class module CConsultant
Option Explicit

Implements IEmployee

Private sName As String
Private cSalary As Currency

Private Property Get IEmployee_Name() As String
	IEmployee_Name = sName
End Sub

Private Property Get IEmployee_Salary() As Currency
	IEmployee_Salary = cSalary
End Sub

Private Sub IEmployee_ReadFromDB()
	...   '** read from a database into private members
End Sub

Private Sub IEmployee_IssuePaycheck()
	...   '** issue employee's paycheck
End Sub

Observe that every member in the class is labeled private! Clients thus cannot couple to CConsultant in any way, allowing it to evolve freely. Compatibility is maintained by continuing to implement IEmployee.

In general, clients now have a choice when accessing a class: to use its default interface or to use any one of the custom interfaces it implements. This choice is expressed by declaring your reference variables of the appropriate interface. For example, here we are accessing a CConsultant object through the IEmployee interface:

Dim rEmp As IEmployee    '** reference to custom interface
Set rEmp = New CConsultant '** class that implements this interface

rEmp.ReadFromDB
txtName.Text = rEmp.Name
txtSalary.Text = Format(rEmp.Salary, "currency")

This situation is depicted in Figure 2.3. Note that the CConsultant object publicizes two interfaces: a default and IEmployee. VB classes always define a default interface, enabling clients to use class-based references:

Dim rEmp2 As CConsultant '** class-based reference = default interface
Set rEmp2 = ...

Figure 2.3 Referencing an object through a custom interface

This is true regardless of whether the interface is empty, which it is in the case of CConsultant because the class contains no public members. The variable rEmp2 is thus useless, because there are no properties or methods to access.

Now that we can define, implement, and use custom interfaces, you may be wondering: How exactly does all this help me evolve my system more easily? Whenever you need to change a private implementation detail, merely recompile and redeploy the component (be sure to read rule 2-5 before recompiling COM components in VB). And when you need to make an interface change, simply introduce a new custom interface. In other words, suppose you want to evolve the CConsultant class by applying some bug fixes as well as by making a few interface changes. You would define a new interface, IEmployee2, implement it within CConsultant, apply the other bug fixes, recompile, and redeploy.

When existing clients come in contact with instances of the revised class, the result is shown in Figure 2.4 (notice the third lollipop).

Figure 2.4 An existing client referencing a new version of class CConsultant

By introducing new interfaces, classes evolve to support new clients while remaining compatible with existing ones. Note that you have two choices when defining a new interface: It is completely self-contained or it works in conjunction with other interfaces. For example, suppose the motivation for IEmployee2 is to add parameters to the method ReadFromDB, and also to add a method for issuing a bonus. In the first approach, you redefine the entire interface:

'** class module IEmployee2 (self-contained)
Option Explicit

Public Property Get Name() As String    '** unchanged
End Sub

Public Property Get Salary() As Currency  '** unchanged
End Sub

Public Sub ReadFromDB(rsCurRecord As ADODB.Recordset)
End Sub

Public Sub IssuePaycheck()         '** unchanged
End Sub

Public Sub IssueBonus(cAmount As Currency)
End Sub

And then your classes implement both. For example, here's the start of the revised CConsultant class:

'** class module CConsultant (version 2)
Option Explicit

Implements IEmployee
Implements IEmployee2
 .
 .
 .

Although the class contains some redundant entry points (Name, Salary, and IssuePaycheck are identical in both interfaces), the advantage is that clients need to reference only one interface—either IEmployee or IEmployee2. The alternative approach is to factor your interfaces, such that each new interface includes only the changes and the additions. In this case, IEmployee2 would contain just two method signatures:

'** class module IEmployee2 (factored)
Option Explicit

Public Sub ReadFromDB(rsCurRecord As ADODB.Recordset)
End Sub

Public Sub IssueBonus(cAmount As Currency)
End Sub

This eliminates redundancy in the class, but requires more sophisticated programming in the client. For example, here's the revised client code for reading an employee from a database and displaying their name and salary:

Dim rEmp As IEmployee     '** one reference var per interface
Dim rEmp2 As IEmployee2

Set rEmp = New CConsultant   '** create object, access using IEmp
Set rEmp2 = rEmp        '** access same object using IEmp2

rEmp2.ReadFromDB ...      '** read from DB/RS using IEmp2
txtName.Text = rEmp.Name    '** access properties using IEmp
txtSalary.Text = Format(rEmp.Salary, "currency")

This is depicted in Figure 2.5. Note that both variables reference the same object, albeit through different interfaces.

Figure 2.5 Each interface requires its own reference variable in the client

As your system evolves, different versions of clients and classes may come in contact with one another. For example, it's very common for classes to gain functionality over time, and thus for a single client to interact with numerous iterations of a class. This implies the need for a mechanism by which a compiled client, already deployed in production, can determine what functionality an object provides; i.e., what interfaces it currently implements. Such a mechanism, based on run-time type information (RTTI), is provided by every COM object and is accessed using VB's TypeOf function.

Suppose our system contains a number of different employee classes: CConsultant, CTechnical, CAdministrative, and so forth. All such classes implement IEmployee, but currently only a few have been revised to implement IEmployee2. Now, suppose the task at hand is to send out a bonus to every employee who is not a consultant. Assuming the employee objects are stored in a collection, we can iterate through the collection and simply check the interfaces published by each object:

Public Sub SendOutBonuses(colEmployees As Collection, _
             cAmount As Currency)
	Dim rEmp As IEmployee, rEmp2 As IEmployee2

	For Each rEmp in colEmployees
		If TypeOf rEmp Is CConsultant Then '** no bonus for you
			'** skip
		Else '** issue this employee a bonus...
			If TypeOf rEmp Is IEmployee2 Then '** use interface
				Set rEmp2 = rEmp
				rEmp2.IssueBonus cAmount
			Else '** issue bonus the old-fashioned way
				<human intervention is required>
			End If
		End If
	Next rEmp
End Sub

Even though the default interface CConsultant is empty, we use it as a marker interface to identify consultants uniquely. Of the remaining employees (all of whom receive a bonus), we check for the IEmployee2 interface and apply the IssusBonus method if appropriate. Failing that, human intervention is required because the employee object does not provide an automatic mechanism. The beauty of TypeOf is that it is a run-time mechanism: The next time you execute it, it will respond True if the class has been revised to implement that interface. Thus, as more and more classes implement IEmployee2 over time, SendOutBonuses will demand less and less human intervention.

The previous discussion reveals another advantage of custom interfaces— polymorphism (see rule 1-7 for a more precise definition). If you think of custom interfaces as reusable designs, then it makes perfect sense for different classes to implement the same interface. This leads to plug-compatible components, and a powerful, polymorphic style of programming in the client in which code is (1) reusable across different classes and (2) resilient to change as classes come and go. For example, consider once again a system with numerous employee classes that all implement IEmployee. As implied by Figure 2.6, our client-side code is compatible with any of these employee classes. Thus, if we need to pay everyone, this is easily done using the IssuePaycheck method implemented by each class:

Public Sub PayEveryone(colEmployees As Collection)
	Dim rEmp As IEmployee

	For Each rEmp in colEmployees
		rEmp.IssuePaycheck
	Next rEmp
End Sub

Figure 2.6 Custom interfaces encourage polymorphism

In other words, IssuePaycheck is polymorphic and can be applied without concern for the underlying object type. Furthermore, if new employee classes are added to the system, as long as each class implements IEmployee, then the previous code will continue to function correctly without recompilation or modification. As you can imagine, given a large system with many employee types and varying payment policies, polymorphism becomes a very attractive design technique.

Lest we all run out and start redesigning our systems, note that custom interfaces come at a price. They do require more effort, because each interface is an additional entity that must be maintained. Custom interfaces also complicate the compatibility issue, in the sense that default interfaces are easily extended (as a result of built-in support from VB) whereas custom interfaces are immutable (see rule 2-5 for a detailed discussion of maintaining compatibility in VB). Finally, scripting clients such as Internet Explorer (IE), Active Server Pages (ASP), and Windows Scripting Host (WSH) cannot access custom interfaces directly. They are currently limited to a class's default interface. This last issue is problematic given the importance of scripting clients in relation to the Web. Thankfully, a number of workarounds exist (see rule 4-5) until compiled environments (such as ASP.NET) become available.

Generally, however, the benefits of custom interfaces far outweigh the costs. Custom interfaces force you to separate design from implementation, encouraging you to think more carefully about your designs. They facilitate design reuse as well as polymorphism. Of course, custom interfaces also serve to minimize coupling between clients and classes, allowing your classes to evolve more freely while maintaining compatibility. As a result, you'll be able to "field-replace" components as business rules change or bug fixes are applied, insert new components of like behavior without having to revisit client code, and define new behavior without disturbing existing clients. You should thus consider the use of custom interfaces in all your object-oriented systems, but especially large-scale ones in which design and coupling have a dramatic effect.

Custom interfaces are so important that COM is based entirely on interfaces. Clients cannot access COM objects any other way. Hence, COM programmers are interface-based programmers. In fact, there exists a language, the Interface Description Language (IDL), solely for describing interfaces. Often called "the true language of COM," IDL is what allows a COM object developed in programming environment X to be accessed from a client written in programming environment Y. Although typically hidden from VB programmers, there are definite advantages to using IDL explicitly to describe your custom interfaces. Read on; we discuss this further in the next rule.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020