zoukankan      html  css  js  c++  java
  • 【设计模式】工厂方法和抽象工厂

    一、前言

    依然记得几年前面试被问到工厂方法模式和抽象工厂有什么区别时,我一脸懵逼哑口无言。本文就分别探讨下这两种设计模式。

    二、Factory Method

    工厂方法(Factory Method)模式,将实例的生成交给子类,父类决定实例的生成方式,但不决定所要生成的具体的类。
    这样就可以将生成实例的框架(framework)和实际负责生成实例的类解耦。

    工厂方法的类图如下:

    enter description here
    enter description here

    Product类和Factory类都是抽象类,属于框架部分,IDCard和IDCardFactory分别为其子类。

    Factory类

    public abstract class Factory {
    
        /**
         * 这里用到了 模板方法模式
         * 使用final修饰 防止被子类重写
         * @param owner
         * @return
         */
        public final Product create(String owner){
            Product product = createProduct(owner);
            registerProduct(product);
    
            return product;
        }
    
        protected abstract Product createProduct(String owner);
    
        protected abstract void registerProduct(Product product);
    }
    
    

    该类的create方法定义了生产产品的算法,用到了Template Method模式,只要是Factory Method模式在生成实例时一定会用到Template Method模式。

    Product类

    public abstract class Product {
    
        public abstract void use();
    }
    

    该类用于定义产品的方法和属性

    IDCard

    public class IDCard extends Product {
    
        private String owner;
    
        /**
         * 不用public修饰防止被new
         * @param owner
         */
        IDCard(String owner){
            System.out.println("制作"+ owner + "的ID卡");
            this.owner = owner;
        }
    
        @Override
        public void use() {
            System.out.println("使用"+ owner + "的ID卡");
        }
    
        public String getOwner() {
            return owner;
        }
    
    
    }
    

    这里构造方法不是public是为了防止被new直接创建实例,只能通过IDCardFactory创建。

    IDCardFactory类

    public class IDCardFactory extends Factory {
    
        private List<String> owners = new ArrayList<>();
    
        /**
         * 通过生成IDCard实例来生产产品
         * @param owner
         * @return
         */
        @Override
        protected Product createProduct(String owner) {
    
            return new IDCard(owner);
        }
    
        /**
         * 通过将IDCard的owner保存到owners来注册产品
         * @param product
         */
        @Override
        protected void registerProduct(Product product) {
            owners.add(((IDCard) product).getOwner());
        }
    }
    

    测试类Main

    public class Main {
    
        public static void main(String[] args) {
            Factory factory = new IDCardFactory();
            Product card1 = factory.create("小明");
            Product card2 = factory.create("小红");
            Product card3 = factory.create("小刚");
    
            card1.use();
            card2.use();
            card3.use();
        }
    }
    
    

    运行结果如下:

    制作小明的ID卡
    制作小红的ID卡
    制作小刚的ID卡
    使用小明的ID卡
    使用小红的ID卡
    使用小刚的ID卡
    

    可以看到调用方Main类只用到了框架部分的类(Product和Factory),而不依赖其具体实现,这样当要生成其他类时,框架部分的代码不用修改。

    三、Abstract Factory

    抽象工厂模式(Abstract Factory),抽象工厂的作用是将“抽象零件”组装为“抽象产品”。
    下面的一个示例程序是利用抽象工厂模式,生成如下的网页文件LinkPage.html

    enter description here
    enter description here

    程序的类图如下:

    类图
    类图

    名字 说明
    Item 方便统一处理Link和Tray的类
    Factory 表示抽象工厂的类(制作Link,Tray,Page)
    Link 抽象零件:表示HTML的链接的类
    Tray 抽象零件
    Page 抽象零件:表示HTML页面的类
    ListFactory 表示具体工厂的类
    ListLink 具体零件
    ListTray 具体零件
    ListPage 具体零件:表示HTML页面的类

    Item

      public abstract class Item {
        /**
         * 标题
         */
        protected String caption;
    
        public Item(String caption) {
            this.caption = caption;
        }
    
        /**
         * 子类来实现
         * @return
         */
        public abstract String makeHtml();
    }
    
    

    Link

    public abstract class Link extends Item {
    
        protected String url;
    
        public Link(String url, String caption) {
            super(caption);
            this.url = url;
        }
    
    }
    

    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);
        }
    
    }
    

    Page

    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);
        }
    
        /**
         * 一个简单的Template Method模式的方法
         */
        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();
    }
    

    抽象工厂Factory

    public abstract class Factory {
    
        public static Factory getFactory(String className) {
            Factory factory = null;
            try {
                // 通过反射生成实例
                factory = (Factory) Class.forName(className).newInstance();
            } catch (ClassNotFoundException e) {
                System.out.println("没有找到 " + className + " 类");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return factory;
        }
    
    
        public abstract Link createLink(String url, String caption);
    
        public abstract Tray createTray(String caption);
    
        public abstract Page createPage(String title, String author);
    }
    

    ListLink类

    public class ListLink extends Link {
    
        public ListLink(String url, String caption) {
            super(url, caption);
        }
    
        @Override
        public String makeHtml() {
            return "<li><a href= "" + url + "">" + caption + "</a></li>
    ";
        }
    }
    

    ListTray

    public class ListTray extends Tray {
    
        public ListTray(String caption){
            super(caption);
        }
    
        @Override
        public String makeHtml() {
            StringBuilder builder = new StringBuilder();
            builder.append("<li>
    ");
            builder.append(caption +"
    ");
            builder.append("<ul>
    ");
            Iterator it = tray.iterator();
            while (it.hasNext()){
                Item item = (Item) it.next();
                builder.append(item.makeHtml());
            }
            builder.append("</ul>
    ");
            builder.append("</li>
    ");
            return builder.toString();
        }
    }
    

    ListPage

    public class ListPage extends Page {
    
        public ListPage(String title, String author) {
            super(title, author);
        }
    
        @Override
        public String makeHtml() {
            StringBuilder builder = new StringBuilder();
            builder.append("<html><head><title>" + title + "</head></title>
    ");
            builder.append("<body>
    ");
            builder.append("<h1>" + title + "</h1>");
            builder.append("<ul>
    ");
            Iterator it = content.iterator();
            while (it.hasNext()) {
                Item item = (Item) it.next();
                builder.append(item.makeHtml());
            }
            builder.append("</ul>
    ");
            builder.append("<hr><address>" + author + "</address></hr>");
            builder.append("</body></html>
    ");
            return builder.toString();
        }
    }
    

    ListFactory

    public class ListFactory extends Factory {
    
        @Override
        public Link createLink(String url, String caption) {
            return new ListLink(url, caption);
        }
    
        @Override
        public Tray createTray(String caption) {
            return new ListTray(caption);
        }
    
        @Override
        public Page createPage(String title, String author) {
            return new ListPage(title, author);
        }
    }
    

    测试类Main

    public class Main {
        public static void main(String[] args) {
    
            Factory factory = Factory.getFactory("cn.sp.abstract_factory.listfactory.ListFactory");
    
            Link people = factory.createLink("http://www.people.com.cn", "人民日报");
            Link gmw = factory.createLink("http://www.gmw.cn", "光明日报");
    
    
            Link us_yahoo = factory.createLink("http://www.yahoo.com/", "Yahoo!");
            Link jp_yahoo = factory.createLink("http://www.yahoo.jp/","Yahoo!Japan");
            Link excite = factory.createLink("http://www.excite.com/","Excite");
            Link google = factory.createLink("http://www.google.com/","Google");
    
            Tray trayNews = factory.createTray("日报");
            trayNews.add(people);
            trayNews.add(gmw);
    
            Tray trayYahoo = factory.createTray("Yahoo!");
            trayYahoo.add(us_yahoo);
            trayYahoo.add(jp_yahoo);
    
            Tray search = factory.createTray("检索引擎");
            search.add(trayYahoo);
            search.add(excite);
            search.add(google);
    
            Page page = factory.createPage("LinkPage","杨文轩");
    
            page.add(trayNews);
            page.add(search);
    
            page.output();
    
    
    
        }
    }
    

    运行结果得到如下文件

    1. <html><head><title>LinkPage</head></title> 
    2. <body> 
    3. <h1>LinkPage</h1><ul> 
    4. <li> 
    5. 日报 
    6. <ul> 
    7. <li><a href= "http://www.people.com.cn">人民日报</a></li> 
    8. <li><a href= "http://www.gmw.cn">光明日报</a></li> 
    9. </ul> 
    10. </li> 
    11. <li> 
    12. 检索引擎 
    13. <ul> 
    14. <li> 
    15. Yahoo! 
    16. <ul> 
    17. <li><a href= "http://www.yahoo.com/">Yahoo!</a></li> 
    18. <li><a href= "http://www.yahoo.jp/">Yahoo!Japan</a></li> 
    19. </ul> 
    20. </li> 
    21. <li><a href= "http://www.excite.com/">Excite</a></li> 
    22. <li><a href= "http://www.google.com/">Google</a></li> 
    23. </ul> 
    24. </li> 
    25. </ul> 
    26. <hr><address>杨文轩</address></hr></body></html> 
    27.  

    假如这里需要增加其他工厂如TableFactory,则只需要添加TableLink,TableTray,TablePage(分别为Link,Tray,Page的子类)即可,顶层的抽象类不需要改变。

    所以可以看出抽象工厂模式有如下特点:

    • 易于增加具体的工厂
    • 难以增加新零件

    四、总结

    它们的区别大概如下:
    1.工厂方法只能生成某一种产品,且对应的工厂只有一个。而抽象工厂可以增加其他工厂,产品由很多零件组成,生成各种实例。
    2.工厂方法比较简单,抽象工厂模式更加复杂和灵活。
    3.工厂方法是通过new创建实例,抽象工厂模式是通过反射创建的。

    最后附上完整代码地址

  • 相关阅读:
    形象理解ERP(转)
    禁用windows server 2008 域密码复杂性要求策略
    How to adding find,filter,remove filter on display method Form
    Windows Server 2008 R2激活工具
    How to using bat command running VS development SSRS report
    Creating Your First Mac AppGetting Started
    Creating Your First Mac AppAdding a Track Object 添加一个 Track 对象
    Creating Your First Mac AppImplementing Action Methods 实现动作方法
    Creating Your First Mac AppReviewing the Code 审查代码
    Creating Your First Mac AppConfiguring the window 设置窗口
  • 原文地址:https://www.cnblogs.com/2YSP/p/12740159.html
Copyright © 2011-2022 走看看