Cobol Foro
Navegación en el Foro
Retroceder   Cobol Foro Entornos de desarrollo y compiladores Cobol COBOL - General Object-Oriented COBOL
Object-Oriented COBOL COBOL orientado a objetos. ISO/2002-2014
 
Otros temas que te pueden interesar
Tema Autor Foro Respuestas Último post
[Duda] ¿Qué se hace en CLASS-OBJECT y FACTORY? Kuk Object-Oriented COBOL 14 22 de febrero de 2017 15:49

Respuesta
 
Herramientas

  #1
Antiguo 22 de febrero de 2017, 14:59
Kuk
Administrador
Última Actividad 19.09.2026 20:11
Posts Posts: 2.500
Likes enviados Enviados: 1037
Likes recibidos Recibidos: 1207
Predeterminado Clases abstractas (Abstract Factory)
0 Inactivo Inactivo

Citación del post de Eslopes
Abstract factory

Lets imagine that you have a POS (Point Of Sale) application that supports hardware from a well known supplier. Your most important customer decided to use a different supplier and asked you to adapt your application to use it. You realize that you may need to add support to a third and even a fourth supplier in the future, but you don't want to increase the complexity of your application. What you need is to raise the abstraction bar, isolating the business logic from classes that deal with POS hardware such as keyboards, screens, card readers, receipt printers, barcode scanners etc. A very good solution would be to get rid of "NEW" operator so your application would not be so tighly coupled with any specific class that deals with hardware! How? Meet the Abstract Factory!
This is the Abstract Factory classic definition: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Don't let this intimidate you. Abstract Factories are not only simple, but pretty flexible solutions that comes in handy very often. Once you master that concept you will not help yourself imagining new and creative uses for it.

The checkout

Checkouts usually comprises:
  • computer
  • screen
  • keyboard
  • barcode scanner
  • receipt printer
  • pin pad with Integrated Card Swipe
  • cash drawer
  • credit card reader

Our application should support many preconfigured checkouts, so we would be able to replace a checkout brand with another one without any impact in the business rules. The key here is to keep business logic as simples as possible and completely unaware of which device brand is being used, as long is provides the expected services.

First let see what we are trying to avoid:
Código COBOL:
  1.  CLASS-ID. ProcessOrder AS "NotSoCoolThings.ProcessOrder".
  2.  
  3.        *> ...
  4.  
  5.      method-id. ProcessNewOrder as "ProcessNewOrder".
  6.       *> ...
  7.          procedure division.
  8.         *> ...
  9.         *> creating checkout support classes
  10.         *> (THAT'S EXACTLY WHAT WE DO NOT WANT TO DO!)
  11.  
  12.         if checkoutType = "HP"
  13.             invoke HPFK182AT "NEW" returning cashDrawerHP
  14.             invoke HPFK224AT "NEW" returning receiptPrinterHP
  15.         else
  16.             invoke TeamPos1054258002 "NEW" returning cashDrawerFJ
  17.             invoke TeamPoSFD21 "NEW" returning receiptPrinterFJ
  18.         end-if
  19.  
  20.          *> Loop getting items and printing
  21.        
  22.            *> ...
  23.           *> Just imagine how would be to have another hardware supplier
  24.            if chechoutType = "HP"
  25.  
  26.              invoke receiptPrinterHP "printItem" using item, quantity
  27.            else
  28.              invoke receiptPrinterFJ "printItem" using item, quantity
  29.            end-if  
  30.  
  31.            *> What if you could mix parts?...there would be endless combinations!
  32.  
  33.            if chechoutType = "HP"
  34.  
  35.              invoke cashDrawerHP "OpenDrawer"
  36.            else
  37.              invoke cashDrawerFJ "OpenDrawer"
  38.            end-if  
  39.  
  40.            *> ...
  41.           *> There must be a better way to do this!
  42.  
  43.  
  44.        end method ProcessNewOrder.
  45.    end object.
  46.  END CLASS ProcessOrder.

The code above clearly shows the high dependency of classes that deal with checkout parts. If we add support to a different hardware supplier, our code would suffer with lots of "ifs" to check which equipament is in use. You could make your life easier by forcing those classes to implement a common interface, but still you would need to code a lot of methods to test the interaction between parts and class creation and all that code would go along business rules...creepy!

These will be our checkout systems:

Fujitsu
. Cash drawer - model TeamPos1054258002
. Receipt printer - model TeamPoSFD21

HP
. Cash drawer - model HPFK182AT
. Receipt printer - model HPFK224AT

In addition to get rid of high dependency (and the mess in the business logic) we would like also to define which set of parts our checkout is made of. We are going to use an XML file to define checkout configuration and which one our application is going to use.

APP.config (xml file)
Código XML:
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3.   <checkout>
  4.     <currentSupplier>/configuration/checkout/suppliers/fujitsu</currentSupplier>
  5.     <suppliers>
  6.       <fujitsu>
  7.         <currentSet>/configuration/checkout/suppliers/fujitsu/sets/TeamPos500</currentSet>
  8.         <sets>
  9.           <TeamPos500>
  10.              <cashDrawer>TeamPos1054258002</cashDrawer>
  11.              <receiptPrinter>TeamPoSFD21</receiptPrinter>
  12.            </TeamPos500>
  13.            <TeamPos1000>
  14.              <cashDrawer>TeamPos10PB60014</cashDrawer>
  15.              <receiptPrinter>TeamPoSFD22</receiptPrinter>
  16.            </TeamPos1000>
  17.          </sets>
  18.        </fujitsu>
  19.        <hp>
  20.          <currentSet>/configuration/checkout/suppliers/hp/sets/HPPOS4SmallBusiness</currentSet>
  21.          <sets>
  22.            <HPPOS4SmallBusiness>
  23.              <cashDrawer>HPFK182AT</cashDrawer>
  24.              <receiptPrinter>HPFK224AT</receiptPrinter>
  25.            </HPPOS4SmallBusiness>
  26.          </sets>
  27.        </hp>
  28.      </suppliers>
  29.    </checkout>
  30.    <db>
  31.      <connection>
  32.        <oracle>
  33.          <DataSource>Data Source=TORCL</DataSource>
  34.          <UserId>admin</UserId>
  35.          <Password>myPassword</Password>
  36.        </oracle>
  37.      </connection>
  38.    </db>
  39.  </configuration>

The XML currently defines two suppliers: Fujitsu and HP. Each supplier could have multiple sets, but only one active. A global setting defines what would be the current supplier used by the app.


The abstract factory

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:

Código COBOL:
  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.

Miniatura de Adjuntos
Pulsar la imagen para la versión amplia
Nombre:  AbstractFactoryUML.gif
Vistas: 168
Tamaño:  8,2 KB  



NORMAS DEL FORO - para garantizar el buen funcionamiento del Foro.
¿Te han ayudado? NO TE OLVIDES de darle a
¿Quieres dirigirte a alguien en tu post? Notifícale haciendo clic en su Nick
Kuk is offline   Responder Con Cita
  #2
Antiguo 22 de febrero de 2017, 15:03
Kuk
Administrador
Última Actividad 19.09.2026 20:11
Posts Posts: 2.500
Likes enviados Enviados: 1037
Likes recibidos Recibidos: 1207
Predeterminado Continuación...
0 Inactivo Inactivo

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

Código COBOL:
  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:

Código COBOL:
  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:

Código COBOL:
  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

So, here is our abstract factory in action. You will notice that we are no longer directly instantiating the driver´s classes. Actually, that code has no idea which driver has been choosen. This has been delegated to the concrete factory. One very insteresting aspect is that our checkout parts can talk each other (for instance, when closing a sale, the receipt printer would open the cash drawer automatically).

Código COBOL:
  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.

Abstract Factories are eveywhere

ATMs, RTS games, DB connections, web frameworks and many more applications uses that useful pattern. Some examples:

Spring.Net (Web Framework)
.Net ADO.Net
Microsoft COM (yes, even the COM implements that pattern)


Download the source

Cool things with OO Cobol - Source Code


Some references in the web

Abstract Factory .NET Design Pattern in C# and VB - dofactory.com
Abstract factory pattern - Wikipedia



NORMAS DEL FORO - para garantizar el buen funcionamiento del Foro.
¿Te han ayudado? NO TE OLVIDES de darle a
¿Quieres dirigirte a alguien en tu post? Notifícale haciendo clic en su Nick
Kuk is offline   Responder Con Cita
Respuesta



Derechos de Publicación
No puedes publicar nuevos temas
No puedes publicar posts/responder
No puedes adjuntar archivos
No puedes editar tus posts

BB code is habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado

Saltar a Foro


La franja horaria es GMT +2. Ahora son las 14:54.
Powered by: vBulletin, Versión 3.8.7
Derechos de Autor ©2000 - 2026, Jelsoft Enterprises Ltd.