一天一个设计模式——Abstract Factory抽象工厂模式

Posted zheng-hong-bo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一天一个设计模式——Abstract Factory抽象工厂模式相关的知识,希望对你有一定的参考价值。

一、模式说明

  前面学习了工厂方法(Factory Method)模式。在工厂方法模式中,在工厂方法模式中,父类决定如何生成实例,但并不决定所要生成的具体类,具体的处理交由子类来处理。这里学习的抽象工厂方法模式中,抽象工厂使用抽象的零件组装成抽象的产品。即使用包含特定的方法接口零件,将零件组装成抽象产品。

二、模式类图:

技术图片

  上面的类图中包含两个包:包含抽象工厂,抽象零件,抽象产品的类所在的包以及具体工厂实现类的包。

三、代码示例

1、Item类:

技术图片
package com.designpattern.cn.abstractfactorypattern.abstractfactory;

//抽象的零件Item
public abstract class Item 
    protected String caption;
    public Item(String caption)
        this.caption = caption;
    
    public abstract String makehtml();
View Code

Item类是下面两个产品的父类,其中的MakeHtml是抽象方法,需要在子类中实现。

2、Link类:

技术图片
package com.designpattern.cn.abstractfactorypattern.abstractfactory;

//抽象的零件Link
public abstract class Link extends Item 
    protected String url;
    public Link(String caption, String url)
        super(caption);
        this.url = url;
    
View Code

Link类被定义为抽象类,初看似乎并不包含抽象方法,但是,Link类继承了抽象类Item,且没有实现MakeHtml抽象方法,则Link类还是一个抽象类。

3、Tray类:

技术图片
package com.designpattern.cn.abstractfactorypattern.abstractfactory;

import java.util.ArrayList;

//抽象的Tray类
public abstract class Tray extends Item 
    protected ArrayList tray = new ArrayList();
    public Tray(String caption)
        super(caption);
    
    public void add(Item item)
        tray.add(item);
    
View Code

同样的Tray类也是抽象类。

4、抽象的产品Product类:

技术图片
package com.designpattern.cn.abstractfactorypattern.abstractfactory;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;

public abstract class Page 
    protected String title;
    protected String author;
    protected ArrayList content = new ArrayList();
    public Page(String title, String author)
        this.title = title;
        this.author = author;
    
    public void add(Item item)
        content.add(item);
    
    public void output()
        try 
            String filename = title + ".html";
            Writer writer = new FileWriter(filename);
            writer.write(this.makeHtml());
            writer.close();
            System.out.println(filename + " 编写完成!");
        catch (IOException e) 
            e.printStackTrace();
        
    
    public abstract String makeHtml();
View Code

5、抽象工厂Factory类:

技术图片
package com.designpattern.cn.abstractfactorypattern.abstractfactory;

public abstract class Factory 
    public static Factory getFactory(String classname)
        Factory factory = null;
        try 
            factory = (Factory)Class.forName(classname).newInstance();
        catch (ClassNotFoundException | InstantiationException | IllegalAccessException e)
            e.printStackTrace();
        
        return factory;
    

    public abstract Link createLink(String caption, String url);
    public abstract Tray createTray(String caption);
    public abstract Page createPage(String title, String author);
View Code

该类中使用getFactory方法来根据类名声称具体的工厂示例,该方法通过调用Class类的forName方法动态的读取类信息,接着使用newInstance方法生成类的实例,并将其作为返回值给调用者。

  需要注意的是,虽然getFactory方法生成的是具体工厂的实例,但由于返回值的类型是抽象工厂类型。createLink、createTray、createPage方法是用于在抽象工厂中生成抽象零件和产品的抽象方法,具体的实现交由子类,不过在这里确定了方法的名字和签名。

 

  看完了模式的抽象类,接下来看具体的实现类:

1、具体的工厂ListFactory类:

技术图片
package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Factory;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Link;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Page;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Tray;

public class ListFactory extends Factory 
    public Link createLink(String caption, String url)
        return new ListLink(caption, url);
    

    public Tray createTray(String trayname)
        return new ListTray(trayname);
    

    public Page createPage(String title, String author)
        return new ListPage(title, author);
    
View Code

2、具体的零件ListLink类:

技术图片
package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Link;

public class ListLink extends Link 
    public ListLink(String caption, String url) 
        super(caption, url);
    

    @Override
    public String makeHtml() 
        return "<li><a href=\\"" + url + "\\">" + caption + "</a></li>\\n";
    
View Code

3、具体的零件ListTray类:

技术图片
package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Item;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Tray;

import java.util.Iterator;

public class ListTray extends Tray 
    public ListTray(String caption) 
        super(caption);
    

    @Override
    public String makeHtml() 
        StringBuffer buffer = new StringBuffer();
        buffer.append("<li>\\n");
        buffer.append(caption + "\\n");
        buffer.append("<ul>\\n");
        Iterator iterator = tray.iterator();
        while(iterator.hasNext())
            Item item = (Item) iterator.next();
            buffer.append(item.makeHtml());
        
        buffer.append("</ul>\\n");
        buffer.append("</li>\\n");
        return buffer.toString();
    
View Code

4、具体的零件LIstPage类:

技术图片
package com.designpattern.cn.abstractfactorypattern.listfactory;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Item;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Page;

import java.util.Iterator;


public class ListPage extends Page 
    public ListPage(String title, String author) 
        super(title, author);
    

    @Override
    public String makeHtml() 
        StringBuffer buffer = new StringBuffer();
        buffer.append("<html><head><title>" + title + "</title></head>\\n");
        buffer.append("<body>\\n");
        buffer.append("<h1>" + title + "</h1>\\n");
        buffer.append("<ul>\\n");
        Iterator iterator = content.iterator();
        while(iterator.hasNext())
            Item item = (Item)iterator.next();
            buffer.append(item.makeHtml());
        
        buffer.append("</ul>\\n");
        buffer.append("<hr><address>" + author + "</address>");
        buffer.append("</body></html>\\n");
        return buffer.toString();
    
View Code

5、运行结果:

Main类代码:

技术图片
package com.designpattern.cn.abstractfactorypattern;

import com.designpattern.cn.abstractfactorypattern.abstractfactory.Factory;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Link;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Page;
import com.designpattern.cn.abstractfactorypattern.abstractfactory.Tray;
import com.designpattern.cn.abstractfactorypattern.listfactory.ListFactory;

public class Main 
    public static void main(String[] args)
        System.out.println(ListFactory.class.getName());
        if(args.length!= 1)
            System.out.println("Usage: java Main class.name.of.ConcreateFactory");
            System.out.println("Example 1: java Main listFactory.ListFactory");
            System.out.println("Example 2: java Main tablefactory.TableFactory");
            System.exit(0);
        
        Factory factory = Factory.getFactory(args[0]);

        Link people = factory.createLink("People‘s Daily", "http://www.people.com.cn/");
        Link gmw = factory.createLink("gmw", "http://www.gmw.cn/");
        Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
        Link jp_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.co.jp/");
        Link excite = factory.createLink("Excite", "http://www.excite.com");
        Link google = factory.createLink("Google", "http://www.google.com/");

        Tray traynews = factory.createTray(" Daily ");
        traynews.add(people);
        traynews.add(gmw);

        Tray trayyahoo = factory.createTray("Yahoo!");
        trayyahoo.add(us_yahoo);
        trayyahoo.add(jp_yahoo);

        Tray traysearch = factory.createTray("Search engeen");
        traysearch.add(trayyahoo);
        traysearch.add(excite);
        traysearch.add(google);

        Page page = factory.createPage("LinkPage", "Rumble");
        page.add(traynews);
        page.add(traysearch);
        page.output();
    
View Code

 

技术图片

四、模式中的角色

  • AbstractProduct抽象产品角色:AbstractProduct负责定义AbstractFactory抽象工厂角色所生成的零件和产品接口。(程序示例中的LInk、Tray、Page类)
  • AbstractFactory抽象工厂角色:负责定义用于生成抽象产品的接口。
  • Client委托者角色:Client调用AbstractFactory和Abstract Product角色的接口来进行工作。程序中由Main扮演该角色。

五、抽象工厂模式的特点

  • 易于增加具体的工厂:很清楚实现一个具体的工厂应该实现哪些方法,对于示例,当需要增加新的工厂时,需要做的就是编写Factory、Link、Tray、Page这几个类的子类。任何时候都不需要修改抽象类和Main类。
  • 难以增加新零件:如果要在一个抽象工厂中增加零件,这时候除了修改抽象工厂,还要修改所有的实例工厂。

六、相关的设计模式

  • Builder模式:分阶段的制作复杂实例
  • Factory Method模式:在抽象工厂Abstract Factory模式中,生成零件和产品可能会使用到工厂方法模式
  • Composite模式
  • Singleton模式

最后,抽象工厂模式在Spring中也是有用到的,所以需要好好消化一下。

 

以上是关于一天一个设计模式——Abstract Factory抽象工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

抽象工厂模式(Abstract Factory)

Abstract Factory模式(设计模式)

Abstract Factory模式(设计模式)

12-Factor与云原生

抽象工厂模式(Abstract Factory)

设计模式抽象工厂模式(Abstract Factory)