百摩网
当前位置: 首页 生活百科

新出的地狱模式(别再到处new对象了)

时间:2023-06-20 作者: 小编 阅读量: 1 栏目名: 生活百科

顾名思义,工厂模式中的“工厂”指的是创建对象的工厂,它提供了一种创建对象的最佳方式,也就是工厂模式。所以,简单工厂只适用于固定类型对象的创建。

你还在到处 new 对象吗?

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

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

什么是工厂模式?

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

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

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

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

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

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

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

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

1、简单工厂

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

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

新建客户基类:

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

/** * 客户 * @author: 栈长 * @from: Java技术栈 */@Data@NoArgsConstructor@AllArgsConstructorpublic 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 {@Overridepublic Customer create(String type, String name) {return new Merchant(type, name);}}

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

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

新建代理商工厂实现类:

/** * 代理商工厂 * @author: 栈长 * @from: Java技术栈 */public class AgentFactory implements CustomerFactory {@Overridepublic 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@NoArgsConstructorpublic 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 {@Overridepublic Customer createCustomer(String type, String name) {return new Merchant(type, name);}@Overridepublic CustomerExt createCustomerExt() {return new MerchantExt();}}

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

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

新建代理商工厂实现类:

/** * 代理商工厂 * @author: 栈长 * @from: Java技术栈 */public class AgentFactory implements CustomerFactory {@Overridepublic Customer createCustomer(String type, String name) {return new Agent(type, name);}@Overridepublic 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技术栈” 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重大家的劳动成果和知识产权,抄袭必究。

    推荐阅读
  • 完美关系在那个台几点播出(你知道吗)

    接下来我们就一起去研究一下吧!完美关系在那个台几点播出当代都市题材电视剧《完美关系》的播出时间:2020年2月18日,首播平台:湖南卫视、爱奇艺、腾讯视频。若是VIP会员24点更新,非会员次日24点观看,2018年7月拍摄,由浙江金溪影视有限公司制作,制作周期12个月,该剧由安建导演,主演:黄轩,佟丽娅,陈数。

  • 堂哥的儿子是我的外甥还是侄子(堂哥的儿子是我的外甥还是侄子呢)

    亦称朋友的儿子,属于客套话,而哥哥的小孩其实就是弟兄的孩子,所以叫“侄子”最恰当不过。姑侄对称,与亲兄弟之子无关。在此之前,兄弟之子称为兄子和弟子,多用作亲属的“转述叙称”称谓。

  • 晨跑和夜跑哪个更减肥瘦身(晨跑和夜跑哪个减肥更快)

    但是对于减肥的人而言,还是要有所限制。

  • 施瓦辛格成功绝非偶然(从穷小子到国际巨星)

    在加入美国国籍后,他就报名参加了美国举办的国际健美比赛,而在本场比赛上,施瓦辛格凭借着接近完美的男性身材而获得了比赛冠军,也因此得到了健美先生的称号。施瓦辛格心里一直有一个梦想——成为美国总统。施瓦辛格弃影从政,成功当选州长施瓦辛格在健美界和影坛所取得的成就也使得他闻名世界,他所积攒下的财富也使得他跻身亿万富翁。另外施瓦辛格还提出了使用清洁能源等政策,为此他还放弃

  • 汉服简介(汉服的介绍)

    与汉人一词类似,汉服中的“汉”字的词义外延亦存在着由汉朝扩大为整个民族指称的过程。汉服“始于黄帝,备于尧舜”,源自黄帝制冕服。定型于周朝,并通过汉朝依据四书五经形成完备的冠服体系,成为神道设教的一部分。汉服还通过华夏法系影响了整个汉文化圈,亚洲各国的部分民族如日本、朝鲜、越南、蒙古、不丹等等服饰均具有或借鉴汉服特征。

  • 山楂的保存方法(山楂的保存方法简述)

    下面内容希望能帮助到你,我们来一起看看吧!山楂的保存方法对于已经切开的山楂,想要保存可以放进盐水中,也可放在阳光下晾晒,让水分尽快蒸发掉。完整的山楂保存可以装入塑料袋中,扎紧袋口放进冰箱冷藏。在容器底部放一层细沙将山楂装入,再放一层细沙密封保存。最简单的方法是放入保鲜膜中,把里面空气放干净,密封袋口保存。

  • 象棋中的马怎么算撇脚(撇脚的具体情况如下)

    以下内容大家不妨参考一二希望能帮到您!象棋中的马怎么算撇脚比如马要向前跳!那马前面也就是马头上如果有棋子就是挡马脚!无论马往哪边跳!马前面有一颗棋子挡着,比如想向前跳,紧挨着马的正前方有一颗棋子,都叫撇脚马,同理,你想向左跳,紧挨着马的左方有一颗棋子也叫撇脚马。

  • 赘婿楼舒婉为什么要杀死家人 赘婿楼舒婉报仇了吗

    在对方强占檀儿时,被宁毅给撞见了,一向有仇必报的他,自然要将楼家给灭掉。之前宣威营的小头目绑走了苏檀儿,最终卖给了楼书恒。之后楼舒婉制作了防水衣送给了刘西瓜,刘西瓜又给了宁毅。之后宁毅发现了防水衣的秘密,急冲冲的跑到了楼家的布店,刚好撞见楼书恒在欺负苏檀儿。如此看来,这一切都是楼舒婉布下的局,就是为了弄死自己的哥哥和父亲。之后他的所作所为,都是为了报复自己之前遭遇的不公。

  • 自制瓷砖胶(瓷砖胶配方及制作方法)

    接下来我们就一起去研究一下吧!自制瓷砖胶先将冷水按比例加入到容器内,开启搅拌机再将胶粉徐徐撒入,高速搅拌10-15分钟即为胶水。批重钙、滑石粉,每1000公斤水加107胶粉13-14公斤、杀菌防腐剂3公斤,或加入甲醛2.5-3公斤,制成胶水。批硅酸盐灰白水泥:每1000公斤水直接加入107胶粉10-11公斤,制成胶水。

  • 研教学评一体化(备教学)

    只有经历这一大循环的教学,才能呈现一种持续评价教与学的目标达成度、教与学的进步度、决定教与学的需求,并实现螺旋上升的态势,使教与学和质量评价更有意义。所以,在“备、教、学、评一体化”教学指导下的教学新格局,应该是一个高效的课堂。