views:

385

answers:

3

Hi: I want to know when we need to use the abstract factory pattern.

Here is an example,I want to know if it is necessary.

The UML

THe above is the abstract factory pattern, it is recommended by my classmate. THe following is myown implemention. I do not think it is necessary to use the pattern.

And the following is some core codes:

    package net;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;



public class Test {
    public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException {
        DaoRepository dr=new DaoRepository();
        AbstractDao dao=dr.findDao("sql");
        dao.insert();
    }
}

class DaoRepository {
    Map<String, AbstractDao> daoMap=new HashMap<String, AbstractDao>();
    public DaoRepository () throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException  {
        Properties p=new Properties();
        p.load(DaoRepository.class.getResourceAsStream("Test.properties"));
        initDaos(p);
    }
    public void initDaos(Properties p) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        String[] daoarray=p.getProperty("dao").split(",");
        for(String dao:daoarray) {
            AbstractDao ad=(AbstractDao)Class.forName(dao).newInstance();
            daoMap.put(ad.getID(),ad);
        }
    }
    public AbstractDao findDao(String id) {return daoMap.get(id);}

}
abstract class AbstractDao {
    public abstract String getID();
    public abstract void insert();
    public abstract void update();
}
class SqlDao extends AbstractDao {
    public SqlDao() {}
    public String getID() {return "sql";}
    public void insert() {System.out.println("sql insert");}
    public void update() {System.out.println("sql update");}
}
class AccessDao extends AbstractDao {
    public AccessDao() {}
    public String getID() {return "access";}
    public void insert() {System.out.println("access insert");}
    public void update() {System.out.println("access update");}
}

And the content of the Test.properties is just one line:

dao=net.SqlDao,net.SqlDao

So any ont can tell me if this suitation is necessary?


-------------------The following is added to explain the real suitation--------------

I use the example of Dao is beacuse it is common,anyone know it.

In fact,what I am working now is not related to the DAO,I am working to build a Web

service,the web serivce contains some algorithms to chang a file to other format,

For example:net.CreatePDF,net.CreateWord and etc,it expose two interfaces to client:getAlgorithms and doProcess.

The getAlogrithoms will return all the algorithms's ids,each id is realted to the corresponding algorithm.

User who call the doProcess method will also provide the algorithm id he wanted.

All the algorithm extends the AbstractAlgorithm which define a run() method.

I use a AlogrithmsRepository to store all the algorithms(from

the properties file which config the concrete java classes of the algorithms by the web

service admin).That's to say, the interface DoProcess exposed by the web service is

executed by the concrete alogrithm.

I can give a simple example: 1)user send getAlgorithms request:

http://host:port/ws?request=getAlgorithms

Then user will get a list of algorithms embeded in a xml.

<AlgorithmsList>
  <algorithm>pdf</algorithm>
  <algorithm>word<algorithm>
</AlgorithmsList>

2)user send a DoProcess to server by:

http://xxx/ws?request=doProcess&amp;alogrithm=pdf&amp;file=http://xx/Test.word

when the server recieve this type of requst,it will get the concrete algorithm instance according to the "algorithm" parameter(it is pdf in this request) from the AlgorithmRepostory. And call the method:

AbstractAlgorithm algo=AlgorithmRepostory.getAlgo("pdf");
algo.start();

Then a pdf file will be sent to user.

BTW,in this example, the each algorithm is similar to the sqlDao,AccessDao. Here is the image:

The design image

Now,does the AlgorithmRepostory need to use the Abstract Factory?

+2  A: 

If you ask to compare 2 designs from UML, 2nd API on UML have following disadvantage:

  • caller needs to explicitly specify type of DAO in call to getDAO(). Instead, caller shouldn't care about type of DAO it works with, as long as DAO complies with interface. First design allows caller simply call createDAO() and get interface to work with. This way control of which impl to use is more flexible and caller don't have this responsibility, which improves overall coherence of design.
Victor Sorokin
But the abstract factory also need caller care about the type.http://java.dzone.com/articles/design-patterns-abstract-factoryThis article,under the main method,user have to konw that there are two typs,MsWindowsWidgetFactory and MACOSWindowsWidgetFactory.
hguser
@hguser - somewhere up the call chain, someone needs to specify the type, but an abstract factory's *immediate* caller doesn't need to know the type of the factory.
Jeff Sternal
@Jeff Sternal -http://dpaste.org/GyRC/Line 9 and 13, we call the factory manully by the "new" word.
hguser
@hguser: the point of the abstract factory is to decouple the **`GUIBuilder`** from the particular implementation (not your high-level application - it doesn't actually *use* the factory). The repository approach you've proposed requires the `GUIBuilder` to know what type of factory you want.
Jeff Sternal
+2  A: 

The main difference between the two approaches is that the top one uses different DAO factories to create DAO's while the bottom one stores a set of DAO's and returns references to the DAO's in the repository.

The bottom approach has a problem if multiple threads need access to the same type of DAO concurently as JDBC connections are not synchronised.

This can be fixed by having the DAO implement a newInstance() method which simply creates and returns a new DAO.

abstract class AbstractDao {
    public abstract String getID();
    public abstract void insert();
    public abstract void update();
    public abstract AbstractDao newInstance();
}
class SqlDao extends AbstractDao {
    public SqlDao() {}
    public String getID() {return "sql";}
    public void insert() {System.out.println("sql insert");}
    public void update() {System.out.println("sql update");}
    public AbstractDao newInstance() { return new SqlDao();}
}

The repository can use the DAO's in the repository as factories for the DAO's returned by the Repository (which I would rename to Factory in that case) like this:

public AbstractDao newDao(String id) {
    return daoMap.containsKey(id) ? daoMap.get(id).newInstance() : null;
}

Update

As for your question should your web-service implement a factory or can it use the repository like you described? Again the answer depends on the details:

  • For web-services it is normal to expect multiple concurrent clients
  • Therefore the instances executing the process for two clients must not influence eachother
  • Which means they must not have shared state
  • A factory delivers a fresh instance on every request, so no state is shared when you use a factory pattern
  • If (and only if) the instances in your repository are stateless your web-service can also use the repository as you describe, for this they probably need to instantiate other objects to actually execute the process based on the request parameters passed
rsp
@rsp-Thanks for fixing my problem.In fact,what I want to make clear is that when to use a Abstract Factory,that's to say we assume the two ways mentioned above can not cause some thread problems. well,if the problems does not exist,why do we use the Abstract Factory?In the Ab.Fatory pattern,the different products are created by different factories,in the following way(the one you fixed),the products are created by a Repository(the DaoRepository in the example),so,what's the difference? WHen the Repository create a new instance,it also does not know which object it is creating,isn't it?
hguser
@hguser, As always it depends on context. If your need is to instantiate a set on objects that are used by the application there is nothing wrong with a repository which creates instances based on configuration and hands out references to these objects. In this case the "factory" is part of the repository initialisation. An object factory which creates new instances is another use case, which might cover more uses.
rsp
@rsp-So for the situation I added(the example of the web service),if one want to use the abstract factory in the AlgorithmsRepository,how to implement it? I really want to make it clearly about the differences from the same example. Thanks.
hguser
@rsp--Yes,I have consider the data sharing problem,in fact,it need some share datas,for example, more than one user call the "pdf" algorithm to createPDF,the algorithm of PDF should have a queue of tasks, I set this tasklist using a static field--"private static ArrayList taskList". And from your detail reply, I feel I know something, but I can not hold it.So,I wonder if one can give a simple design using AbstractFoctory pattern for my siutation.?
hguser
@hguser, you are on the right track. The best way to move forward is to just try and build what you designed up to now. If you get stuck ask a new question showing your code where you think the problem is.
rsp
@rsp. --Thanks :). In fact,the system has been implemented yet, and the web service is already running. The reason I ask this problem is someone have suggest me to use the Abstract Factory. Actually,in my opinion, if the AbstractFactory is better, I will have a try to change the system.
hguser
A: 

Abstract Factory is useful if you need to separate multiple dimensions of choices in creating something.

In the common example case of windowing systems, you want to make a family of widgets for assorted windowing systems, and you create a concrete factory per windowing system which creates widgets that work in that system.

In your case of building DAOs, it is likely useful if you need to make a family of DAOs for the assorted entities in your domain, and want to make a "sql" version and an "access" version of the entire family. This is I think the point your classmate is trying to make, and if that's what you're doing it's likely to be a good idea.

If you have only one thing varying, it's overkill.

Don Roby