• 4.0 Architecture


    A programming architecture refers to the underlying structure, or design, of an entire system. More specifically, a programs structure consists of software elements and their interrelationships as well as the properties of the elements and relationships.

    In this module we are using a particular architecture for the applications that we will be developing. There will be an application class that simply creates a controller object and executes its "run()" method. The controller constructor method "Controller()" builds the model (in-memory), i.e. creates objects. During this process the system may use an "InputHelper" object to seek information from the user or it may load the data for the model from file storage.

    The controller "run()" method then:
    displays the current state of the model objects
    displays a menu and accepts user choice
    executes a private method based on the user choice
    typically add and delete options
    persists the model data to file storage

    The following class diagrams details aspects of a system's architecture:

    system's architecture class diagram

    Insurance App class diagram

    Appointment App class diagram
  • 4.1 Customer Projects Application Example


    In this example an app is required to manage customers and their projects. A Customer object defines a customer id, their name and a list of projects that associated with the customer. The application has the following required functionality:
    load customer details from a file into a collection
    display customer collection details
    display a menu and accept use choice
    add a project to a customer
    remove a project from a customer
    store customer collection details to a file

    We can use the same architectural pattern as before (above examples), i.e. create an app class where execution begins (the "main()" method). Then create a run method which calls the constructor of the controller class "Controller()". The controller class will then:
    load customer details to build the customer collection
    display customer collection details
    utilises "toString()" methods
    display menu and accepts user choice
    call add, remove or store methods dependent on the users choice

    public class Customer {
       private final int customerId;
       private String customerName;
       private ArrayList<String>
                       customerProjects;
        
       private static int 
               lastCustomerIdAllocated = 0;
    

    Example class diagram:

    customerProject App class diagram
  • 4.2 Class Breakdown (App & Controller)


    CustomerProjects App

    methods:
    main()
    run()

    responsibility:
    create and run controller object

    CustomerProjectController screenshot

    attributes:
    customer collection (repository)

    methods:
    CustomerProjectsController()
    loadCustomersFromTextFile()
    storeCustomersToTextFile()
    run()
    displayCustomerProjectsMenu()
    addProjectToCustomer()
    removeProjectFromCustomer()

    responsibilities:
    load and build model
    implement app functionality
    (use case functionality)

    As we have seen apps require a number of classes. We want to make these classes as cohesive and independent as possible for two reasons. Firstly, it aids reuse of code as opposed to duplication but the main reason is to aid separation of concerns.

    Separation of concerns is a design principle which encourages the development of an app using units (classes) which focus on single aspects of the functionality and overlap as little as possible, i.e. each unit (class) should focus on one clear aspect of the required functionality. Currently our controller class fulfills two aspects, it loads and build the model and it Implement the app’s functionality. Separation of concerns would indicate that we should separate this functionality into distinct classes. Since the controller implements the use case(s) of the required system we should abstract the loading and building of the model into a separate class.

    "In software engineering, a software design pattern is a general reusable solution to a commonly occuring problem within a given context in a software design. It is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situation. Design patterns are formalised best practices that the programmer can use to solve common problems when designing an application ot system."

    Wikipedia

  • 4.3 Repository Pattern


    A repository object can be created and used to separate the code that retrieves & persists data (used to populate the model) from the business logic that works on the model. A multitude of authors have described this pattern including Martin Fowler:

    Martin Fowler WebSite

    We are going to develop a Repository class and make it as generic as possible.

    Consider the required functionality, we want to be able to:
    define attributes which will represent the model
    typically a collection of model objects
    load data from a file to populate the collection
    in a constructor method
    add an item to the collection
    remove an item from the collection
    retrieve all items from the collection
    retrieve a specified item from the collection
    store the collection to a file
    produce a String version of the state of the collection
    i.e. model objects

    Consequently, we will develop the following class:

    Repository Class

    attributes:
    items collection

    methods:
    Repository()
    getItems()
    setItems()
    getItem()
    add()
    remove()
    store()
    toString()

    responsibilities:
    load, build and maintain in-memory model objects

    public class Repository { 
       private List<Customer> items;    
            
       public Repository() {
          this.items = new ArrayList<>();
       } 
        
       public Repository(List<Customer> items) {        
          this.items = items;
       } 
        
       public Repository(String filename) {
          this();
          … 
       } 
    

    We can also use a constructor to load the repository from a pre-existing file:

    public Repository(String filename) {
       this();
       try (BufferedReader br = new BufferedReader(new FileReader(filename))) { 
          String[] temp;
          String line = br.readLine();
          while(line!=null){
             temp=line.split(Character.toString(DELIMITER));        
             int customerId = Integer.parseInt(temp[0]);
             String customerName = stripQuotes(temp[1]);
             Customer customer = new Customer(customerId, customerName);
             int noProjects = Integer.parseInt(temp[2]);            
             for (int i=0; i<noProjects; i++) {
                String project = stripQuotes(temp[i+3]);
                customer.addProjectToCustomer(project);
             }
             this.items.add(customer);                
             line = br.readLine();                
          }
          br.close();
          …
    }
    

    public List<Customer> getItems() {        
       return this.items;
    } 
             
    public Customer getItem(int id) {
       for (Customer item:this.items) {
          if (item.getCustomerId() == id)
             return item;
       }
       return null;
    }
    public void add(Customer item) {
       this.items.add(item);
    } 
           
    public void remove(int id) {
       Predicate<Customer> customerPredicate = c->c.getCustomerId() == id;       
       this.items.removeIf(customerPredicate);
    }   
    

    public void store(String filename) {
       try (
             PrintWriter output = new PrintWriter(filename)) {    
          output.print(this.toString(DELIMITER));
          output.close();
       }
       … 
    } 
    

    We have written the code as 'generic' as possible to minimize references to Customer to aid reuse. However, ideally we would like a Repository class which could be instantiated with any type of model object.

    Revisiting the design guideline of separation of concerns leads us to the conclusion that this version of the Repository class actually both, loads and stores the model data from/to file and manages the in-memory model objects i.e. collection.

    Let’s consider a pattern which will separate these...
  • 4.4 Data Access Object Pattern (DAO)


    A DAO pattern is often used to provide access to persistence mechanisms (e.g. a database), it is commonly described in the context of database access.

    “An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data” - Martin Fowler

    Persistence mechanisms are characteristics of states that outlive the process that created them. More simply they are characteristics of states that have been archived as stored data. There are several ways in which data can be stored:

    Text Files
    Delimited (CSV)
    XML
    JSON
    Object Files
    Databases
    Relational, Object Oriented, NoSQL

    Our current approach involves generating/amending constructors and store methods for each type of persistence. Other persistence methods would also include other methods and configurations. It would beneficial if we could abstract the persistence issues away from the repository class into dedicated classes. This would allow the repository class to concentrate on fields and methods to access/update the repository, i.e. the collection of model objects. A Data Access Object Pattern provides guidance on how to separate persistence logic from the model. This helps to enforce the separation of concerns guideline where individual classes concentrate on specific pieces of functionality, as well as providing opportunities for reuse as well and a cleaner design.

    "The Data Access Object (DAO) pattern is now a widely accepted mechanism to abstract away the details of persistence in an application. The idea is that instead of having the domain logic communicate directly with the databse, file system, web service, or whatever persistence mechanism your application uses, the domain logic speaks to a DAO layer instead. This DAO layer then communicates with the underlying persistence system or service."

    DAO Pattern

    🔗 http://tutorials.jenkov.com/java-persistence/dao-design-pattern.html

    Class Diagram

    Class Diagram
    🔗 http://www.corej2eepatterns.com/Patterns2ndEd/DataAccessObject.htm

    BusinessObject (“Client”)
    represents data client
    object requires access to data source to obtain and store data
    may be implemented as a session bean, entity bean, or POJO

    DataAccessObject
    primary object of pattern
    abstracts underlying data access implementation for BusinessObject
    enable transparent access to data source
    BusinessObject also delegates data load and store operations to DataAccessObject

    DataSource
    data source implementation
    e.g. RDBMS, OODBMS, XML repository, flat file system
    also be another system (legacy/mainframe), service (B2B service or credit card bureau), or some kind of repository (LDAP)

    TransferObject
    used as a data carrier
    DAO may use to return data to client
    DAO may also receive data from client in a Transfer Object to update data in data source

    This approach has both benefits and drawbacks.
    benefits:
    changing the persistence mechanism is limited to changing the DAO
    there is no change to domain logic
    the DAO layer normally contains less classes
    e.g. Hotel & Room classes are incorporated in a HotelDAO

    problems:
    connection scoping
    transaction scoping
    exception handling
  • 4.5 Interface


    We are going to define an "Interface" to specify the methods that we need to handle persistence issues, i.e. "load()" and "store()". An Interface is a useful mechanism for doing this as it does not specify how these methods will be implemented, i.e. whether we are using a text file or an object file or other persistence mechanism, in other words we can implement the Interface in many ways. An Interface cannot be instantiated so we will need an implementation class to flesh out the methods and define any attributes.

    public interface DAOInterface {
       public Repository load(String filename);
       public void store(String filename, Repository repository);
    }
    

    Again we have written this to be generic ensuring not to mention the Customer class. As noted an interface is generally a list of methods that any implementation class must implement. For a text file implementation we will need to flesh out the load() and store() methods, i.e. move the code from the Repository class.

    Repository Class

    The implementation class is said to realize the interface. It use the "implements" keyword and overrides the methods specified in the "Interface" definition:

    public class DAOTextImpl implements DAOInterface {
    static final char DELIMITER=',';

    @Override
       public Repository load(String filename) {
          Repository repository = new Repository();
          …
          return repository;
       }
        
       @Override
       public void store(String filename,
                         Repository repository) { … }
    

    We have abstracted the persistence details from the Repository constructor and store() methods, and we replaced the code with code to create an appropriate dao object from which we can call the load() or store() method as required.

    public Repository(String filename) {
    		   this();
    		   DAOTextImpl dao = new DAOTextImpl();
    		   this.items = dao.load(filename).getItems();
    		} 
    		public void store(String filename) {
     		  DAOTextImpl dao = new DAOTextImpl();
    		   dao.store(filename, this);
    		}
    

    This approach means we can have multiple persistence mechanisms in a program. For example to change the persistence mechanism to object files:

    Create a DAOObjImpl class which implements the DAOInterface
    Change the type of the dao object in the Repository load() and store() methods to this new class

    For this app we have created folders to bring together classes and interfaces which share common functionality and persistence approach
    app
    customerprojects
    model
    repositories
    controllers
    daos
    helpers

    Java Package Structure

    Class diagram:
    Class Diagram