The main interface of this design pattern is the abstract factory interface. This is the interface that will be used by the client app to create concrete factories. Lets call it ICheckoutAbstractFactory:
1: INTERFACE-ID. ICheckoutAbstractFactory as "AFP.ICheckoutAbstractFactory".
2: environment division.
3: configuration section.
4: repository.
5: interface ICashDrawer as "AFP.ICashDrawerAbstractProduct"
6: interface IReceiptPrinter as "AFP.IReceiptPrinterAbstractProduct".
7: *> here would enter any other abstract product that is part of a checkout.
8:
9: procedure division.
10: method-id. CreateCashDrawer as "CreateCashDrawer".
11: data division.
12: linkage section.
13: 01 cashDrawer usage object reference ICashDrawer.
14:
15: procedure division returning cashDrawer.
16: *> Interfaces do not contain any logic, just the desired interface
17:
18: end method CreateCashDrawer.
19: method-id. CreateReceiptPrinter as "CreateReceiptPrinter".
20: data division.
21: linkage section.
22: 01 receiptPrinter usage object reference IReceiptPrinter.
23:
24: procedure division returning receiptPrinter.
25: *> Interfaces do not contain any logic, just the desired interface
26:
27: end method CreateReceiptPrinter.
28:
29: END INTERFACE ICheckoutAbstractFactory.
The concrete factory
A concrete factory implements the abstract factory "create" methods. It will be the only point in the code that we need to update after add a new checkout system. This is a very specialized class which only responsibility is to create the proper parts. Our application has two concrete factories: FujitsuConcreteFactory and HPConcrete Factory. If you analyse the code carefully you maybe realize that we could implement only one factory ;)
1: CLASS-ID. FujitsuConcreteFactory as "AFP.FujitsuConcreteFactory".
2: environment division.
3: configuration section.
4: repository.
5: interface ICheckoutAbstractFactory as "AFP.ICheckoutAbstractFactory"
6: interface ICashDrawerAbstractProduct as "AFP.ICashDrawerAbstractProduct"
7: interface IReceiptPrinterAbstractProduct as "AFP.IReceiptPrinterAbstractProduct"
8:
9: *>Cash drawers classes
10: class ClassTeamPos1054258002 as "AFP.Drivers.CashDrawers.TeamPoS105428002"
11: class ClassTeamPos10PB60014 as "AFP.Drivers.CashDrawers.TeamPoS0PB60014"
12:
13: *>Receipt printers classes
14: class ClassTeamPOSFD21 as "AFP.Drivers.ReceiptPrinters.TeamPOSFD21"
15: class ClassTeamPOSFD22 as "AFP.Drivers.ReceiptPrinters.TeamPOSFD22"
16:
17: class ClassUtils as "AFP.Utils"
18: class CollectionHashTable as "System.Collections.Hashtable"
19: class �SystemString as "System.String"
20: class �SystemObject as "System.Object".
21: object. implements ICheckoutAbstractFactory.
22: data division.
23: working-storage section.
24: 01 checkoutHardware usage object reference SystemString.
25: 01 receiptPrinterName pic n(80) value spaces.
26: 01 cashDrawerName pic n(80) value spaces.
27: 01 driver usage object reference SystemObject.
28: 01 drivers �usage object reference CollectionHashTable.
29:
30: procedure division.
31: method-id. NEW.
32: procedure division.
33: *> Getting all drivers at once
34: invoke ClassUtils "GetCheckoutDrivers" returning drivers.
35:
36: end method NEW.
37:
38: method-id. CreateCashDrawer as "CreateCashDrawer".
39: data division.
40: linkage section.
41: 01 cashDrawer usage object reference ICashDrawerAbstractProduct.
42:
43: procedure division returning cashDrawer.
44:
45: *> Get cashDrawer and receipt drivers
46:
47: set driver to drivers::"get_Item"("CashDrawer") 48: set cashDrawerName to driver as SystemString
49:
50: *> creating the cash drawer class defined in the configuration file
51: evaluate cashDrawerName
52: when n"TeamPos1054258002"
53: invoke ClassTeamPos1054258002 "NEW" returning cashDrawer
54: when n"TeamPos10PB60014"
55: invoke ClassTeamPos10PB60014 "NEW" returning cashDrawer
56: end-evaluate
57:
58: end method CreateCashDrawer.
59: method-id. CreateReceiptPrinter as "CreateReceiptPrinter".
60: data division.
61: linkage section.
62: 01 receiptPrinter usage object reference IReceiptPrinterAbstractProduct.
63:
64: procedure division returning receiptPrinter.
65: *> Get cashDrawer and receipt drivers
66:
67: set driver to drivers::"get_Item"("ReceiptPrinter") 68: set receiptPrinterName to driver as SystemString
69:
70: *> creating the receipt printer class defined in the configuration file
71:
72: evaluate receiptPrinterName
73: when n"TeamPoSFD21"
74: invoke ClassTeamPoSFD21 "NEW" returning receiptPrinter
75: when n"TeamPoSFD22"
76: invoke ClassTeamPoSFD22 "NEW" returning receiptPrinter
77: end-evaluate
78:
79: end method CreateReceiptPrinter.
80: end object.
81: END CLASS FujitsuConcreteFactory.
The abstract product
An abstract product is the interface that allow the concrete factory to load the proper product. Without that interface, the concrete factory would be useless (or much more complex than the necessary). Below the interface for Receipt Printers:
1: INTERFACE-ID. IReceiptPrinterAbstractProduct as "AFP.IReceiptPrinterAbstractProduct".
2: environment division.
3: configuration section.
4: repository.
5: interface ICashDrawerAbstractProduct as "AFP.ICashDrawerAbstractProduct"
6:
7: class SystemString as "System.String"
8: class ClassUser as "AFP.User"
9: class ClassCompany as "AFP.Company"
10: class ClassProduct as "AFP.Product".
11:
12: procedure division.
13: method-id. StartNewSale as "StartNewSale".
14: data division.
15: linkage section.
16: 01 company �usage object reference ClassCompany.
17: 01 user usage object reference ClassUser.
18:
19: procedure division using by value company, by value user.
20:
21: end method StartNewSale.
22:
23: method-id. RegisterItem as "RegisterItem".
24: data division.
25: linkage section.
26: 01 product�usage object reference ClassProduct.
27: 01 quantity usage binary-long signed.
28:
29: procedure division using by value product, by value quantity.
30:
31: end method RegisterItem.
32: method-id. PrintTotal as "PrintTotal".
33: data division.
34: linkage section.
35: 01 cashDrawer usage object reference ICashDrawerAbstractProduct.
36:
37: procedure division using by value cashDrawer.
38:
39: end method PrintTotal.
40:
41: *> ... and any other interfaces that you may need to implement
42: *> (e.g. CancelItem, CancelTransaction, PrintDiscount etc
43:
44: END INTERFACE IReceiptPrinterAbstractProduct.
The concrete product
A concrete product in our checkout architecture take care of all communications with the hardware, so we are calling them drivers in this context. Here is the a concrete product for a Fujitsu Cash Drawer:
1: CLASS-ID. TeamPoS0PB60014 as "AFP.Drivers.CashDrawers.TeamPoS0PB60014".
2: environment division.
3: configuration section.
4: repository.
5: interface ICashDrawerAbstractProduct as "AFP.ICashDrawerAbstractProduct".
6: object. implements ICashDrawerAbstractProduct.
7:
8: procedure division.
9: method-id. OpenDrawer as "OpenDrawer".
10:
11: procedure division.
12:
13: display "Fujitsu cash drawer TeamPoS0PB60014 opened..."
14:
15: *> here would go specific cash drawer API calls...
16:
17: end method OpenDrawer.
18:
19: end object.
20: END CLASS TeamPoS0PB60014.
Using our factory 1: CLASS-ID. ProcessOrder AS "NowYouAreTalking.ProcessOrder".
2: *> ...
3: method-id. ProcessNewOrder as "ProcessNewOrder".
4: *> ...
5: procedure division.
6:
7: *> ...
8: *> Creating a concrete factory
9: invoke ClassFujitsuConcreteFactory "NEW" returning checkout
10:
11: *> Creating cash drawer and receipt printer classes
12: invoke checkout "CreateCashDrawer"returning cashDrawer
13: invoke checkout "CreateReceiptPrinter" returning receiptPrinter
14: *> ...
15:
16: *> Using receipt printer
17: invoke receiptPrinter "StartNewSale" using aCompany, aUser
18: invoke receiptPrinter "RegisterItem" using aProduct, 10
19:
20: *> close order and open the cashDrawer
21: invoke receiptPrinter "PrintTotal" using cashDrawer
22: end method ProcessNewOrder.
23: end object.
24: END CLASS ProcessOrder.