• 设计模式——抽象工厂模式


    Abstract Factory模式,即抽象工厂模式,该模式要求Factory类为抽象的,并且里面的生产出来的产品也是抽象的!

    这里需要着重说的一点就是,抽象类和抽象方法的作用——规范了子类的实现,以及当使用时候,直接可以面向抽象父类/接口的方式进行操作,利用多态的面向对象特性。

    同时,需要注意的是,所有抽象的类全都是封装到一个包中的,与调用的不同。

    这种方式的一个应用就是JDBC的规范,SUN公司在jdk中提供了相应的接口/抽象父类作为规范,而对应的数据库厂商则根据这个接口/抽象父类去写具体实现。这样一来,我们在操作数据库时候,直接使用sun公司提供的抽象父/接口,而不需要关注具体是怎么实现的,因为不管什么样的数据库,我们操作的代码都是一样的,唯一不同的就是导包不同。

    在本次是实例中,使用的一个抽象工厂,以及三个抽象产品。最终希望的就是在E盘的根目录,生成对应的HTML页面。

    在factory抽象类的包中,定义了抽象的类

    • Factory 抽象的 工厂类
    package site.wangxin520.gof.abstractfactory.factory;
    
    /**
     * 抽象工厂的类,制作Link,Tray,Page
     * 定义了抽象方法,规范了实现该方法的具体工厂类
     * @author wangXgnaw
     *
     */
    public abstract class Factory {
    
        /**
         * 根据实例工厂的全限定名,获取工厂实例,采用反射的方法
         * @param factoryName 实例化工厂的全限定名
         * @return Factory 返回实例化工厂
         */
        public static Factory getFactory(String factoryName) {
            
            Factory factory=null;
            try {
    //            factory = (Factory) Class.forName(factoryName).newInstance();
                factory = (Factory) ClassLoader.getSystemClassLoader().loadClass(factoryName).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return factory;
        }
        
        /**
         * 抽象类,规范了创建Link和Tray和Page的方法
         * @param caption
         * @param url
         * @return
         */
        public abstract Link createLink(String caption,String url);
        public abstract Tray createTray(String caption);
        public abstract Page createPage(String title,String author);
    }
    • Item 所有产品类的父类
    package site.wangxin520.gof.abstractfactory.factory;
    
    /**
     * 方便统一处理Link和Tray的类
     * Item类是,Link和Tray的父类
     * @author wangXgnaw
     *
     */
    public abstract class Item {
    
        //caption字段表示标题
        protected String caption;
        
        /**
         * 构造函数
         * @param caption
         */
        public Item(String caption){
            this.caption=caption;
        }
        
        /**
         *  制作html,返回HTML文件的内容
         *  本方法是抽象方法,需要子类去实现
         * @return String
         */
        public abstract String makeHTML();
    }
    • Link抽象的工厂中的产品,用于记录超链接的
    package site.wangxin520.gof.abstractfactory.factory;
    
    /**
     * Link类抽象的表示HTML的链接的类
     * @author wangXgnaw
     *
     */
    public abstract class Link extends Item{
        
        //url字段保存的是超链接所指向的地址
        protected String url;
    
        /**
         * 构造函数,由于继承了一个抽象类,且抽象父类只有一个有参构造
         * 所以,构造函数必须提供,并且调用的是父类的有参构造
         * @param caption
         * @param url
         */
        public Link(String caption,String url) {
            super(caption);
            this.url=url;
        }
        
    }
    • Tray抽象工厂的产品,用于存放元素的
    package site.wangxin520.gof.abstractfactory.factory;
    
    import java.util.ArrayList;
    
    /**
     * Tray类也要是一个抽象类
     * Tray类表示的是一个含有多喝Link类和Tray类的容器
     * Tray有托盘的意思
     * @author wangXgnaw
     *
     */
    public abstract class Tray extends Item{
    
        //用于保存Tray和Link类,作为容器
        protected ArrayList<Item> tray=new ArrayList<>();
        
        /**
         * 构造方法,调用父类的有参构造
         * @param caption
         */
        public Tray(String caption) {
            super(caption);
        }
        
        /**
         * 使用add方法将Link和Tray类集合在一起
         * @param item
         */
        public void add(Item item){
            tray.add(item);
        }
    }
    • Page抽象工厂的产品,页面相关
    package site.wangxin520.gof.abstractfactory.factory;
    
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.ArrayList;
    
    /**
     * 抽象的表示HTML页面的类
     * @author wangXgnaw
     *
     */
    public abstract class Page {
    
        //姓名和作者
        protected String title;
        protected String author;
        
        //用于保存页面中的元素
        protected ArrayList<Item> content=new ArrayList<>();
        
        /**
         * page的构造,传入标题和作者
         * @param title
         * @param author
         */
        public Page(String title,String author){
            this.title=title;
            this.author=author;
        }
        
        /**
         * 在页面中存入元素
         * @param item
         */
        public void add(Item item){
            content.add(item);
        }
        
        /**
         * 向文件中写入,这里固定是向E盘根目录中写入一个html文件
         */
        public void output(){
            String filename=title+".html";
            
            FileWriter fw=null;
            try {
                fw = new FileWriter(new File("E:/",filename));
                fw.write(this.makeHTML());
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(filename+"编写完成");
        }
    
        /**
         * 定义一个制作HTML的方法为子类提供规范
         * @return
         */
        public abstract String makeHTML();
    }

    在其他包中,实现了以上的接口,方便使用

    • ListFactory工厂类的具体实现
    package site.wangxin520.gof.abstractfactory.listfactory;
    
    import site.wangxin520.gof.abstractfactory.factory.Factory;
    import site.wangxin520.gof.abstractfactory.factory.Link;
    import site.wangxin520.gof.abstractfactory.factory.Page;
    import site.wangxin520.gof.abstractfactory.factory.Tray;
    
    /**
     * 表示具体工厂的类
     * 制作ListLink,ListTray,ListPage
     * @author wangXgnaw
     *
     */
    public class ListFactory extends Factory{
    
        /**
         * 返回具体的ListLink实例,下同
         */
        @Override
        public Link createLink(String caption, String url) {
            return new ListLink(caption, url);
        }
    
        @Override
        public Tray createTray(String caption) {
            return new ListTray(caption);
        }
    
        @Override
        public Page createPage(String title, String author) {
            return new ListPage(title, author);
        }
    
    }
    • ListLink上面Link类的具体实现
    package site.wangxin520.gof.abstractfactory.listfactory;
    
    import site.wangxin520.gof.abstractfactory.factory.Link;
    
    /**
     * 具体零件,表示HTML的连接的类
     * @author wangXgnaw
     *
     */
    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><br/>";
        }
    
    }
    • ListTray Tray类的具体实现
    package site.wangxin520.gof.abstractfactory.listfactory;
    
    import site.wangxin520.gof.abstractfactory.factory.Item;
    import site.wangxin520.gof.abstractfactory.factory.Tray;
    
    /**
     * 具体零件,表示含有Link和Tray的类
     * 
     * @author wangXgnaw
     *
     */
    public class ListTray extends Tray {
    
        public ListTray(String caption) {
            super(caption);
        }
    
        @Override
        public String makeHTML() {
    
            StringBuilder sb = new StringBuilder();
            sb.append("<li>").append(caption).append("<ul>");
    
            for (Item item : tray) {
                sb.append(item.makeHTML());
            }
    
            sb.append("</ul>").append("</li>");
    
            return sb.toString();
        }
    
    }
    • ListPage Page类的具体实现
    package site.wangxin520.gof.abstractfactory.listfactory;
    
    import site.wangxin520.gof.abstractfactory.factory.Item;
    import site.wangxin520.gof.abstractfactory.factory.Page;
    
    /**
     * 具体零件,表示HTML页面的类
     * @author wangXgnaw
     *
     */
    public class ListPage extends Page{
    
        public ListPage(String title, String author) {
            super(title, author);
        }
    
        @Override
        public String makeHTML() {
            
            StringBuilder sb=new StringBuilder();
            
            sb.append("<html><head><title>"+title+"</title></head>");
            
            sb.append("<body>");
            sb.append("<h1>"+title+"</h1>");
            sb.append("<ul>");
            for (Item item : content) {
                sb.append(item.makeHTML());
            }
            sb.append("</ul>");
            sb.append("<hr>");
            sb.append("<address>"+author+"</address>");
            
            sb.append("</body></html>");
            
            return sb.toString();
        }
    
    }

    测试类以及测试方法

    package site.wangxin520.gof.abstractfactory;
    
    import site.wangxin520.gof.abstractfactory.factory.Factory;
    import site.wangxin520.gof.abstractfactory.factory.Link;
    import site.wangxin520.gof.abstractfactory.factory.Page;
    import site.wangxin520.gof.abstractfactory.factory.Tray;
    
    /**
     * 抽象工厂模式的测试类
     * @author wangXgnaw
     *
     */
    public class Test {
    
        public static void main(String[] args){
            
            //获取工厂实体,参数是实体工厂的全限定名
            Factory factory=Factory.getFactory("site.wangxin520.gof.abstractfactory.listfactory.ListFactory");
            
            //创建超链接
            Link link1 = factory.createLink("王鑫", "http://www.wangxin520.site/");
            Link link2 = factory.createLink("淘宝", "https://www.taobao.com/");
            Link link3 = factory.createLink("京东", "https://www.jd.com/");
            
            //创建序列,并且将超链接放到序列中
            Tray t1 = factory.createTray("主页");
            t1.add(link1);
            Tray t2 = factory.createTray("购物");
            t2.add(link2);
            t2.add(link3);
            
            //创建页面,并且将序列放到页面里面
            Page page = factory.createPage("首页", "王鑫");
            page.add(t1);
            page.add(t2);
            
            //调用page的output()方法去实现写入文件
            page.output();
        }
        
    }

    使用抽象工厂的好处:

    在这种模式下,增加具体的工厂是很容易的,就像如果有新的数据库厂商过来想要开发,直接让他们实现具体的规范即可。

    不过这种模式也是具有缺陷的:

    不方便增加新的产品。

    实现效果:

    • 生成文件

    image

    • 打开效果

    image

  • 相关阅读:
    oc调用rest api
    EF Attach时已存在的处理方式
    设置XtraForm标题居中
    读取DBF文件数据
    GP 环境参数名称列表
    MapWinGIS.ocx 注册
    ArcEngine :The XY domain on the spatial reference is not set or invalid错误
    批量修改sql server 2008的架构
    net不安装Oracle11g客户端直接使用ODAC
    Ninject使用介绍
  • 原文地址:https://www.cnblogs.com/wangxinblog/p/7643813.html
Copyright © 2020-2023  润新知