• 别再到处 new 对象了,试试 3 大工厂模式,真香!!


    你还在到处 new 对象吗?

    单身狗:我没对象,new 怎么了?

    new 对象本身是没问题的,但也不能全部 new 关键字走天下,其实有更好的方式,合适的时候可以试试工厂模式,代码会更优雅。

    什么是工厂模式?

    顾名思义,工厂模式中的 "工厂" 指的是创建对象的工厂,它提供了一种创建对象的最佳方式,也就是工厂模式。

    工厂模式的好处是这些对象不需要暴露自身的创建过程,统一由工厂模式进行创建和提供,隐藏了创建细节,避免了错误的创建对象的形式,也减少了重复创建冗余代码。

    一般情况下,工厂模式可以细分为三类:

    • 简单工厂模式
    • 工厂方法模式
    • 抽象工厂模式

    不过在设计模式权威书籍《设计模式:可复用面向对象软件的基础》一书中,简单工厂模式只是工厂方法模式的一个特例而已。

    所以,从权威的角度说,工厂模式只分为: 工厂模式抽象工厂模式 两大类。

    但不管白猫黑猫,能抓老鼠的就是好猫,设计模式亦是如此,不管怎么分类,这些模式都是程序员们历年过往经验的浓缩,都是值得学习和借鉴的。

    所以,本文栈长从细分的角度带大家来实战下这三个工厂设计模式。

    1、简单工厂

    比如 XX 公司是做支付的,公司有几大类的客户:电商商户、银行客户、代理商……

    创建这些客户的时候我们可以用简单工厂模式来实现看看。

    新建客户基类:

    可以把所有客户公共的信息放到一个客户基类中,比如:客户名、客户类型等,所有的客户继承这个抽象基类。

    /**
     * 客户
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public abstract class Customer {
    
        /**
         * 客户名称
         */
        private String name;
    
        /**
         * 客户类型
         */
        private String type;
    
    }
    

    新建电商商户类:

    /**
     * 商户
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @ToString(callSuper = true)
    public class Merchant extends Customer {
    
        /**
         * 合同类型
         */
        private int contractType;
    
        /**
         * 结算周期(天)
         */
        private int settmentDays;
    
        public Merchant(String name, String type) {
            super(name, type);
        }
    }
    

    新建银行客户类:

    /**
     * 银行客户
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @ToString(callSuper = true)
    public class BankPartner extends Customer {
    
        /**
         * 银行编码
         */
        private String code;
    
        /**
         * 银行地址
         */
        private String address;
    
        public BankPartner(String name, String type) {
            super(name, type);
        }
    }
    

    新建代理商类:

    /**
     * 代理商
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @ToString(callSuper = true)
    public class Agent extends Customer {
    
        /**
         * 代理周期
         */
        private int period;
    
        /**
         * 代理产品
         */
        private int[] products;
    
        public Agent(String name, String type) {
            super(name, type);
        }
    }
    

    新增简单工厂类:

    新建一个简单工厂,提供一个公共静态方法,根据不同的客户类型创建不同的客户。

    /**
     * 客户简单工厂
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class CustomerFactory {
    
        private static Merchant createMerchant(String type, String name) {
            return new Merchant(type, name);
        }
    
        private static BankPartner createBankPartner(String type, String name) {
            return new BankPartner(type, name);
        }
    
        private static Agent createAgent(String type, String name) {
            return new Agent(type, name);
        }
    
        public static Customer create(String type, String name) {
            if ("M".equals(type)) {
                return createMerchant(type, name);
            } else if ("B".equals(type)) {
                return createBankPartner(type, name);
            } else if ("A".equals(type)) {
                return createAgent(type, name);
            }
            return null;
        }
    
    }
    

    新建测试类:

    /**
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class Test {
    
        public static void main(String[] args) {
            Customer merchant = CustomerFactory.create("M", "Java技术栈商户");
            System.out.println(merchant);
    
            Customer bankPartner = CustomerFactory.create("B", "Java技术栈银行客户");
            System.out.println(bankPartner);
    
            Customer agent = CustomerFactory.create("A", "Java技术栈代理商");
            System.out.println(agent);
        }
    
    }
    

    输出结果:

    本节教程所有实战源码已上传到这个仓库:

    https://github.com/javastacks/javastack

    可以看出简单工厂的使用很简单,就是耦合性太高了。

    第一,对象和基类之间是基于继承的。

    第二,工厂类耦合了不同对象的创建,如果对象类型不是固定或者经常变动的,就要频繁修改工厂类,比如我现在要再加一种客户,就必须要改动工厂类,不符开闭原则。

    所以,简单工厂只适用于固定类型对象的创建。

    2、工厂方法

    工厂方法就是为某类产品提供一个工厂接口,然后为每个产品提供一个工厂实现类。

    废话少说,我们将简单工厂的示例用工厂方法再改造一下。

    新建工厂方法接口:

    /**
     * 工厂方法客户接口
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public interface CustomerFactory {
    
        Customer create(String type, String name);
    
    }
    

    新建商户工厂实现类:

    /**
     * 商户工厂
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class MerchantFactory implements CustomerFactory {
    
        @Override
        public Customer create(String type, String name) {
            return new Merchant(type, name);
        }
    
    }
    

    新建银行客户工厂实现类:

    /**
     * 银行客户工厂
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class BankPartnerFactory implements CustomerFactory {
    
        @Override
        public Customer create(String type, String name) {
            return new BankPartner(type, name);
        }
    
    }
    

    新建代理商工厂实现类:

    /**
     * 代理商工厂
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class AgentFactory implements CustomerFactory {
    
        @Override
        public Customer create(String type, String name) {
            return new Agent(type, name);
        }
    
    }
    

    新建测试类:

    /**
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class Test {
    
        public static void main(String[] args) {
            System.out.println("------工厂模式-工厂方法------");
    
            CustomerFactory merchantFactory = new MerchantFactory();
            Customer merchant = merchantFactory.create("M", "Java技术栈商户");
            System.out.println(merchant);
    
            CustomerFactory bankPartnerFactory = new BankPartnerFactory();
            Customer bankPartner = bankPartnerFactory.create("B", "Java技术栈银行客户");
            System.out.println(bankPartner);
    
            CustomerFactory agentFactory  = new AgentFactory();
            Customer agent = agentFactory.create("A", "Java技术栈代理商");
            System.out.println(agent);
        }
    
    }
    

    输出结果:

    本节教程所有实战源码已上传到这个仓库:

    https://github.com/javastacks/javastack

    可以看出,工厂方法也是挺简单易用的,耦合性问题也解决了,每增加一个产品就新增一个产品工厂实现类就行了,扩展性非常好。

    但也有一个问题,如果产品非常多,那势必会造成工厂实现类泛滥,另外一种可怕的场景就是,如果涉及到工厂接口变更,工厂实现类的维护简直就是一种恶梦。

    3、抽象工厂

    工厂方法中一个工厂只能创建一个对象,如果现在每次创建客户的时候都需要同时创建一份客户扩展资料,那就可以考虑使用抽象工厂。

    新建客户扩展基类:

    可以把所有客户公共的扩展信息放到一个客户扩展基类中,比如:客户曾用名、客户扩展说明等,所有的客户继承这个扩展抽象基类。

    /**
     * 客户扩展
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @NoArgsConstructor
    public abstract class CustomerExt {
    
        /**
         * 客户曾用名
         */
        private String formerName;
    
        /**
         * 客户扩展说明
         */
        private String note;
    
    }
    

    新建商户扩展类:

    /**
     * 商户
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @ToString(callSuper = true)
    public class MerchantExt extends CustomerExt {
    
        /**
         * 介绍人
         */
        private int introduceName;
    
        /**
         * 介绍人电话
         */
        private String introduceTel;
    
    }
    

    新建银行客户扩展类:

    /**
     * 银行客户扩展
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @ToString(callSuper = true)
    public class BankPartnerExt extends CustomerExt {
    
        /**
         * 分行个数
         */
        private int branchCount;
    
        /**
         * ATM个数
         */
        private int atmCount;
    
    }
    

    新建代理商扩展类:

    /**
     * 商户
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    @Data
    @ToString(callSuper = true)
    public class AgentExt extends CustomerExt {
    
        /**
         * 来源
         */
        private String source;
    
        /**
         * 资质
         */
        private String certification;
    
    }
    

    新建抽象工厂接口:

    /**
     * 抽象工厂客户接口
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public interface CustomerFactory {
    
        Customer createCustomer(String type, String name);
    
        CustomerExt createCustomerExt();
    
    }
    

    新建商户工厂实现类:

    /**
     * 商户工厂
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class MerchantFactory implements CustomerFactory {
    
        @Override
        public Customer createCustomer(String type, String name) {
            return new Merchant(type, name);
        }
    
        @Override
        public CustomerExt createCustomerExt() {
            return new MerchantExt();
        }
    
    }
    

    新建银行客户工厂实现类:

    /**
     * 银行客户工厂
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class BankPartnerFactory implements CustomerFactory {
    
        @Override
        public Customer createCustomer(String type, String name) {
            return new BankPartner(type, name);
        }
    
        @Override
        public CustomerExt createCustomerExt() {
            return new BankPartnerExt();
        }
    
    }
    

    新建代理商工厂实现类:

    /**
     * 代理商工厂
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class AgentFactory implements CustomerFactory {
    
        @Override
        public Customer createCustomer(String type, String name) {
            return new Agent(type, name);
        }
    
        @Override
        public CustomerExt createCustomerExt() {
            return new AgentExt();
        }
    
    }
    

    新建测试类:

    /**
     * @author: 栈长
     * @from: 公众号Java技术栈
     */
    public class Test {
    
        public static void main(String[] args) {
            System.out.println("------工厂模式-抽象工厂------");
    
            CustomerFactory merchantFactory = new MerchantFactory();
            Customer merchant = merchantFactory.createCustomer("M", "Java技术栈商户");
            CustomerExt merchantExt = merchantFactory.createCustomerExt();
            System.out.println(merchant);
            System.out.println(merchantExt);
    
            CustomerFactory bankPartnerFactory = new BankPartnerFactory();
            Customer bankPartner = bankPartnerFactory.createCustomer("B", "Java技术栈银行客户");
            CustomerExt bankPartnerExt = bankPartnerFactory.createCustomerExt();
            System.out.println(bankPartner);
            System.out.println(bankPartnerExt);
    
            CustomerFactory agentFactory = new AgentFactory();
            Customer agent = agentFactory.createCustomer("A", "Java技术栈代理商");
            CustomerExt agentExt = agentFactory.createCustomerExt();
            System.out.println(agent);
            System.out.println(agentExt);
        }
    
    }
    

    输出结果:

    可以看出,抽象工厂和工厂方法十分类似,只不过抽象工厂里面只生产一个对象,而抽象工厂可以生产多个对象。

    抽象工厂缺点也很明显,第一就是和工厂方法一样工厂类非常多,第二就是扩展非常麻烦,比如我现在要为每个客户类型再加一份客户特殊资料,那所有涉及到抽象工厂的工厂类都要改,是不是要疯了。。

    总结

    如果有多个属于同一种类型的类,可以考虑使用工厂模式,统一提供生成入口,能从一定程度上解耦,扩展方便,也不用再到处 new 对象了。

    但话又说回来,从示例可以看出,如果使用或者设计不当也会带来维护上的工作量。

    本节教程所有实战源码已上传到这个仓库:

    https://github.com/javastacks/javastack

    好了,今天的分享就到这里了,后面栈长我会更新其他设计模式的实战文章,公众号Java技术栈第一时间推送。Java技术栈《设计模式》系列文章陆续更新中,请大家持续关注哦!

    最后,觉得我的文章对你用收获的话,动动小手,给个在看、转发,原创不易,栈长需要你的鼓励。

    版权申明:本文系公众号 "Java技术栈" 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重大家的劳动成果和知识产权,抄袭必究。

    近期热文推荐:

    1.1,000+ 道 Java面试题及答案整理(2021最新版)

    2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!

    3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

    4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!

    5.《Java开发手册(嵩山版)》最新发布,速速下载!

    觉得不错,别忘了随手点赞+转发哦!

  • 相关阅读:
    ElementUI Select下拉框定位问题!
    Vue2 中keyup.enter触发问题!
    Java编写1到100质数之和
    JSP过滤器、Session监听器、Servlet控制器的关系和执行顺序
    EL表达式读取属性不存在的异常,读取类的属性不存在,无法调用到该属性
    Servlet中使用request转发页面引发的500空指针异常
    JSP动态产生的代码,点击显示确认操作,根据操作跳转并传值。
    Linux常用命令大全
    FastAdmin
    Laravel入门
  • 原文地址:https://www.cnblogs.com/javastack/p/15041144.html
Copyright © 2020-2023  润新知