Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Android Design Patterns and Best Practice

You're reading from   Android Design Patterns and Best Practice Create reliable, robust, and efficient Android apps with industry-standard design patterns

Arrow left icon
Product type Paperback
Published in Dec 2016
Publisher Packt
ISBN-13 9781786467218
Length 370 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Kyle Mew Kyle Mew
Author Profile Icon Kyle Mew
Kyle Mew
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Design Patterns FREE CHAPTER 2. Creational Patterns 3. Material Patterns 4. Layout Patterns 5. Structural Patterns 6. Activating Patterns 7. Combining Patterns 8. Composing Patterns 9. Observing Patterns 10. Behavioral Patterns 11. Wearable Patterns 12. Social Patterns 13. Distribution Patterns

The abstract factory pattern

When making a sandwich, bread is only our first and most basic ingredient; we obviously need some kind of filling. In programming terms, this could mean simply building another interface like Bread but calling it Filling and providing it with its own associated factory. Equally, we could create a global interface called Ingredient and have both Bread and Filling as examples of this. Either way, we would have to do a fair bit of re-coding elsewhere.

The design pattern paradigm offers the abstract factory pattern as perhaps the most adaptable solution to this dilemma. An abstract factory is simply a factory that creates other factories. The added layer of abstraction that this requires is amply paid off when we consider how little the top-level control code in our main activity needs to be altered, if at all. Being able to modify low-level structures without affecting those preceding constitutes one of the major reasons for applying design patterns, and when applied to complex architectures, this flexibility can shave many weeks off development time and allow more room for experimentation than other approaches.

Working with more than one factory

The similarities between this next project and the last are striking, as they should be; one of the best things about patterns is that we can reuse structures. You can either edit the previous example or start one from scratch. Here, we will be starting a new project; hopefully that will help make the pattern itself clearer.

The abstract factory works in a slightly different way to our previous example. Here, our activity makes uses of a factory generator, which in turn makes use of an abstract factory class that handles the task of deciding which actual factory to call, and hence which concrete class to create.

As before we will not concern ourselves with the actual mechanics of input and output, but rather concentrate on the pattern's structure. Before continuing, start a new Android Studio project. Call it whatever you choose, set the minimum API level as low as you like, and use the Blank Activity template:

  1. We begin, just as we did before, by creating the interface; only this time, we will need two of them: one for the bread and one for the filling. They should look like this:
    public interface Bread { 
     
        String name(); 
        String calories(); 
    } 
     
    public interface Filling { 
     
        String name(); 
        String calories(); 
    } 
    
  2. As before, create concrete examples of these interfaces. Here, to save space, we will just create two of each. They are all almost identical, so here is just one:
    public class Baguette implements Bread { 
     
        @Override 
        public String name() { 
            return "Baguette"; 
        } 
     
        @Override 
        public String calories() { 
            return " : 65 kcal"; 
        } 
    } 
    
  3. Create another Bread called Brioche and two fillings called Cheese and Tomato.
  4. Next, create a class that can call on each type of factory:
    public abstract class AbstractFactory { 
     
        abstract Bread getBread(String bread); 
        abstract Filling getFilling(String filling); 
    } 
    
  5. Now create the factories themselves. First, BreadFactory:
    public class BreadFactory extends AbstractFactory { 
     
        @Override 
        Bread getBread(String bread) { 
     
            if (bread == null) { 
                return null; 
            } 
     
            if (bread == "BAG") { 
                return new Baguette(); 
            } else if (bread == "BRI") { 
                return new Brioche(); 
            } 
     
            return null; 
        } 
     
        @Override 
        Filling getFilling(String filling) { 
            return null; 
        } 
    } 
    
  6. And then, FillingFactory:
    public class FillingFactory extends AbstractFactory { 
     
        @Override 
        Filling getFilling(String filling) { 
     
            if (filling == null) { 
                return null; 
            } 
     
            if (filling == "CHE") { 
                return new Cheese(); 
            } else if (filling == "TOM") { 
                return new Tomato(); 
            } 
     
            return null; 
        } 
     
        @Override 
        Bread getBread(String bread) { 
            return null; 
        } 
    } 
    
  7. Finally, add the factory generator class itself:
    public class FactoryGenerator { 
     
        public static AbstractFactory getFactory(String factory) { 
     
            if (factory == null) { 
                return null; 
            } 
     
            if (factory == "BRE") { 
                return new BreadFactory(); 
            } else if (factory == "FIL") { 
                return new FillingFactory(); 
            } 
     
            return null; 
        } 
    } 
    
  8. We can test our code just as before, with a debug tag, like so:
    AbstractFactory fillingFactory = FactoryGenerator.getFactory("FIL"); 
    Filling filling = fillingFactory.getFilling("CHE"); 
    Log.d(DEBUG_TAG, filling.name()+" : "+filling.calories()); 
     
    AbstractFactory breadFactory = FactoryGenerator.getFactory("BRE"); 
    Bread bread = breadFactory.getBread("BRI"); 
    Log.d(DEBUG_TAG, bread.name()+" : "+bread.calories()); 
    

When tested, this should produce the following output in the Android monitor:

com.example.kyle.abstractfactory D/tag: Cheese :  : 155 kcal
com.example.kyle.abstractfactory D/tag: Brioche :  : 85 kcal

By the time we reach the end of the book, each ingredient will be a complex object in its own right, with associated imagery and descriptive text, price, calorific value, and more. This is when adhering to patterns will really pay off, but a very simple example like the one here is a great way to demonstrate how creational patterns such as the abstract factory allow us to make changes to our products without affecting client code or deployment.

As before, our understanding of the pattern can be enhanced with a visual representation:

Working with more than one factory

Imagine we wanted to include soft drinks in our menu. These are neither bread nor filling, and we would need to introduce a whole new type of object. The pattern of how to add this is already laid out. We will need a new interface that would be identical to the others, only called Drink; it would utilize the same name() and calories() methods, and concrete classes such as IcedTea could be implemented along exactly the same lines as above, for example:

public class IcedTeaimplements Drink { 
 
    @Override 
    public String name() { 
        return "Iced tea"; 
    } 
 
    @Override 
    public String calories() { 
        return " : 110 kcal"; 
    } 
} 

We would need to extend our abstract factory with something like this:

abstract Drink getDrink(String drinkType); 

We also, of course, need to implement a DrinkFactory class, but this too would have the same structure as the other factories.

In other words, we can add, delete, change, and generally muck around with the nuts and bolts of a project, without ever really having to bother with how these changes are perceived by the higher-level logic of our software.

The factory pattern is one of the most frequently used of all patterns. It can and should be used in many situations. However, like all patterns, it can be overused or underused, if not thought about carefully. When considering the overall architecture of a project, there are, as we shall see, many other patterns at our disposal.

You have been reading a chapter from
Android Design Patterns and Best Practice
Published in: Dec 2016
Publisher: Packt
ISBN-13: 9781786467218
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image