Abstract Factory Design: Replacing if else with enum

When we use Abstract Factory Pattern , we generally have FactoryMaker class which has a getFactory function in which we pass argument and we have switch or if-else logic in the function on the passed parameter to decide which factory to return. Is creating passed parameter an enum or an object and then having the logic of which factory to return inside those object will be better. For example :

Let us say this us our factory maker which are passed enum CountryCode to decide factory.


    public class FacoryMaker {

        public final static FacoryMaker fctry= new FacoryMaker();

        public static RetailFactory getFactory(CountryCode code){
            RetailFactory rt = null;
            if(code == CountryCode.UK){
                rt = new UKFactory();
            }
            if(code == CountryCode.US){
                rt = new USFactory();
            }
            return rt;
        }
    }

Instead of this we will have :


    public class FacoryMaker {

        public final static FacoryMaker fctry= new FacoryMaker();

        public static RetailFactory getFactory(CountryCode code){
            return code.getFactory();
        }
    }

and enum will be modified like this:


    public enum CountryCode {
        US(){
            @Override
            public RetailFactory getFactory() {
                return new USFactory();
            }
        },  
        UK(){
            @Override
            public RetailFactory getFactory() {
                return new UKFactory();
            }
        };  
        public abstract RetailFactory getFactory();
    }

But I don't see this being followed generally. Why is it so? Why can't we make the passing parameter always an object and have the logic inside the object of which factory to get? Can it fail under any abstract factory design. It looks very generic to me. Also by this it is possible to even remove the factory maker and use the object directly to get the Factory instance.


I think that Abstract Factory is a general pattern for all OOP languages. When people describe it, they should show a general implementation which is possible to be applied in all of those languages. Then people follow the pattern, they follow genernal implementation.

And your implementation is using Enum which is specifically supported in Java but not other OOP languages.


Very often in practice, factory methods don't know in advance the implementations. The implementing classes may not exist at the time the factory is created. This is the case for example in service provider frameworks such as the Java Database Connectivity API (JDBC). JDBC defines the interfaces that service providers must implement, but the concrete implementations are not known in advance. This framework allows adding implementations later, for example for database drivers of new cutting edge databases. The service provider framework includes a provider registration API to register implementations (ex: DriverManager.registerDriver ), and a service access API for clients to obtain an instance of the service (ex: DriverManager.getConnection ). It is common to instantiate the service implementation using reflection (ex: Class.forName("org.blah.Driver") ).

Your example is different. You know all the implementation classes you intended. And you are not considering (yet) the pluggability of other implementations. Whether you create the instances using a switch or an enum , it makes little difference. Both alternatives are fine, equivalent.

Another related alternative is that the various methods in Collections do, for example Collections.emptyList() , Collections.singletonList(...) , and so on. The implementations are not decided by a switch, but have explicit names by way of using specialized methods.

When you want to make it possible to use implementations of your interfaces not known in advance, and not hard-coded in your factory, look into service provider frameworks such as JDBC.

But I don't see this being followed generally. Why is it so?

Your technique only works because you know all the implementations of RetailFactory in advance. In frameworks like JDBC, all the implementations of Driver , Connection , and so on, are not known in advance, for all the databases out there, so using such technique with a single enum referencing all implementations is not possible, and not scaleable. So they use a different mechanism, to register and load implementations dynamically at runtime.

Why can't we make the passing parameter always an object and have the logic inside the object of which factory to get?

You can. If you don't need dynamic loading of implementations like JDBC (and most probably don't), your way of using enums has some advantages. For example, your original implementation does rt = ... , which is not as good as doing return ... . Such "mistake" is not possible using your enum solution. On the other hand, if you want dynamic loading, then using an enum will not make much sense.

The bottomline is, there is no big difference between the two alternatives you presented. Both are fine.


When designing software, one aspect to consider is Separation of Concerns it doesn't sound very reasonable to me to let a CountryCode create a RetailFactory . Both concepts have a pretty low cohesion towards each other, which should be avoided.

Further, if you already have a country code, why would you need a factory at all, what's preventing you to call the getFactory method directly? It simply makes no sense.

The CountryCode is merely a hint for the FactoryMaker's getFactory method, how to create the factory. It may even completely ignore the country code. What if there is a country without a RetailFactory? Do you return null ? a DefaultFactory or the Factory of another country?

Of course it is possible to do it that way, but if you look at your code a half year from now, you may think "Wtf? Why the heck did I create the Factory in the Country Code?!"

Besides, the first example you provided seem to be more of a Factory Method than a Factory because the FactoryMaker is not used at all.

链接地址: http://www.djcxy.com/p/96760.html

上一篇: 连接到TFS服务器将关闭Git解决方案

下一篇: 抽象工厂设计:用枚举代替