• No results found

Abstract Factory

In document Leanpub.more.Coding.in.Delphi.2015 (Page 55-60)

Sometimes you want to have a factory that defines a given interface for the creation of an object, but you don’t want to specify the implementation of that interface until you decide at runtime.

The Gang of Four defines the Abstract Factory Pattern as follows:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Of course, an example will do the trick. Let’s imagine the notion of electrical devices that run on batteries.

Here we’ll use interfaces as our abstractions:

IBattery = interface

['{AE55BF10-3945-43BC-886D-AC8556334D55}']

function GetType: string;

end;

IElectricalDevice = interface

['{14655F2F-8B5A-4A45-BC7F-459FEB99F8B6}']

function GetName: string;

procedure UseBattery(aBattery: IBattery);

end;

IElectricalDeviceFactory = interface ['{EFB88733-99B0-4E3C-B626-19D6C6CDA111}']

function CreateBattery: IBattery;

function CreateElectricalDevice: IElectricalDevice;

end;

IBatteryrepresents – yes – a battery, andIElectricalDevicerepresents any device that needs a battery.

However, there are lots of different kinds of devices and lots of different kinds of batteries. Let’s declare a few of them:

TLitiumIonBattery = class(TInterfacedObject, IBattery) function GetType: string;

end;

TCellPhone = class(TInterfacedObject, IElectricalDevice) function GetName: string;

procedure UseBattery(aBattery: IBattery);

end;

TAABatteries = class(TInterfacedObject, IBattery) function GetType: string;

end;

TToyRaceCar = class(TInterfacedObject, IElectricalDevice) function GetName: string;

procedure UseBattery(aBattery: IBattery);

end;

We’ve declared two types of batteries and two types of electrical devices that use different kinds of batteries.

So, what might be a good way to create all the right things in all the right places and at the right times in a way that is decoupled and flexible? We could create an Abstract Factory:

// Abstract Factory

IElectricalDeviceFactory = interface ['{EFB88733-99B0-4E3C-B626-19D6C6CDA111}']

function CreateBattery: IBattery;

function CreateElectricalDevice: IElectricalDevice;

end;

Yep, that’s a factory, and since it is an interface, it is abstract, containing two functions that create a battery and an electrical device for use. By using it, you can implement any battery type and any electrical device that you want.

Now that we have an abstract factory, we can create a “client” class that uses it, and we can do that even before we write any concrete factories. That’s the power and flexibility of factories. Watch:

// Client class TElectrical = class private

FBattery: IBattery;

FElectricalDevice: IElectricalDevice;

public

constructor Create(aElectricalDeviceFactory: IElectricalDeviceFactory);

procedure TurnOnDevice;

end;

constructor TElectrical.Create(aElectricalDeviceFactory: IElectricalDeviceFactory);

begin

inherited Create;

FBattery := aElectricalDeviceFactory.CreateBattery;

FElectricalDevice := aElectricalDeviceFactory.CreateElectricalDevice;

end;

procedure TElectrical.TurnOnDevice;

begin

FElectricalDevice.UseBattery(FBattery);

end;

TElectricalcreates any electrical device for which you have a factory and then lets you power it up. It does all that without actually calling a constructor on anything. It defers to the factory for the creation of the batteries and the actual device.

What is needed now are some concrete factory implementations:

// Concrete Factories

As you can see, each of the factories decides what electrical device will be created and what type of battery that device needs. You could create many more of these similar factories, and pass them toTElectricalwithout changing anything in the existing code.TElectricalcan create any electrical device, even ones that haven’t been invented yet. Expanding the universe of electrical devices involves nothing more than creating new classes. That’s what an abstract factory lets you do.

Here’s the procedure to make it all work:

procedure DoIt;

Electrical := TElectrical.Create(ToyCarFactory);

try

Electrical.TurnOnDevice;

finally

Electrical.Free;

end;

end;

Conclusion

We’ve pretty thoroughly decoupled creation of objects from the classes that use them, eh? (And let’s all say it together: “Loose coupling is good! Tight coupling is bad!”) We’ve created factories, which are classes that take over the responsibility of creating objects so your main classes don’t have that responsibility anymore.

Our general classes no longer depend on concrete classes, but instead can rely on abstractions. And relying on abstractions makes for clean, easy to maintain code. Yay!

Introduction

The next pattern we’ll look at is the Observer Pattern. You should use it when you have one object that needs to notify any number of other objects when events occur. The Observer Pattern creates a one-to-many relationship between an event-generating object and the objects that need to be notified about that event.

The Observer Pattern is a good way to separate your concerns. First, you have a concern of data production.

Data production is useless unless it can be used or displayed in someway. However, there may be any number of ways that you want that data saved, displayed, or otherwise distributed. So the “Subject” – the thing being observed – keeps track of all the “Observers” that want the data. The observers should be separated from the subject via interfaces.

A good way of thinking about the Observer Pattern is to think of magazine subscriptions. You might subscribe to a news magazine that is delivered to you weekly. That magazine is the “Subject” and you are the “Observer.”

You read (observe) the magazine each week as it is delivered. You can stop subscribing at any time. But you aren’t the only subscriber – other people, dentist’s offices, businesses, etc., all might subscribe or stop subscribing at any time. The magazine producer doesn’t know much if anything about where its magazines are going beyond the address, and you don’t know much about what it takes to create the magazine – you just know it shows up each week.

The Observer Pattern is like this – observers can subscribe to the subject, and the subject can notify the subscribers of “news.”

In document Leanpub.more.Coding.in.Delphi.2015 (Page 55-60)