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

新出的地狱模式(别再到处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技术栈” 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重大家的劳动成果和知识产权,抄袭必究。

    推荐阅读
  • 快递员有必要送货上门吗(送货上门成为快递小哥不能承受之重)

    老人家属认为,快递单上标明送货上楼,并且这个快递重22斤,但快递公司却没有履行责任,故应担责,要求快递公司赔偿抚恤金、丧葬费等共计50万元。一部分网友表示,自取快递与老人猝死之间没有法律上的因果关联,快递公司不需负责。12月3日,国家邮政局举办的快递企业座谈会上,为企业未来发展指明了方向,那就是提供个性化、一体化、全球化服务,并推动产品分类、服务分层,向综合快递物流供应商转型。

  • 躺平该怎么办(员工躺平怎么办)

    不公平待遇有些领导在某些事情处理上有所欠缺,员工感觉自己受到了不公平待遇,而出现了心理失衡。提供成长机会公司设立师徒制的传、帮、带机制,即师傅带徒弟,徒弟做好了师傅有奖赏。(由于篇幅原因在此不展开,对“师徒制”感兴趣的朋友可以关注我,后面我们会对相关内容进行详细介绍。公司培训一定要做到人人出力、人人参与,特别是要让业务部门参与进来,会更有落地性。在此过程中,也能发现公司经营中的实际问题,加以解决。

  • 七年级数学下册思维导图全部(初中数学七年级下册各小节详细思维导图)

    最新最全学习资料欢迎戳文末免费领取哦~由于头条号篇幅限制,老师仅展示部分资料内容需要完整版高清资料的家长们,获取方式如下:1.关注转发收藏本文2.私信老师发送:初中数学七年级下册各小节详细思维导图0709按照操作流程即可快速领取资料!

  • 好看简约的网名(好听网名有哪些)

    以下内容大家不妨参考一二希望能帮到您!好看简约的网名樱丸小桃子唇香绕齿柔孤心匠小豆芽曾经沧海窒息。妳終究不是我的孤街浪人设置隐身卿珞.眼角眉梢都是你今晚约吗.哭倒了城墙星星泡饭野性美小熊软糖掉了睡到自然醒往祂怀里撞.国家特级不保护废物本是荒野客.淡忘如思空瓶氧气远赴惊鸿宴.小丸子往复随安

  • 小窗幽记二则解释(为人处世小窗幽记全文及译文)

    作者陈继儒,字仲醇,号眉公,松江华亭人。陈继儒自幼颖异,博学多通,尤工诗善文,书法苏米,兼能绘事,名重一时。屡奉诏征用,皆以疾辞。《小窗幽记》为陈继儒编著的修身处世格言,条条都是人生的回味和处世的领悟。君平之柳,崔护之花,汉宫之流叶,蜀女之飘梧,令后世有情之人咨嗟想慕,托之语言,寄之歌咏。而奴无昆仑,客无黄衫,知己无押衙,同志无虞侯,则虽盟在海棠,终是陌路萧郎耳。

  • 轴承十大品牌榜上有哪些品牌(全球九大知名轴承品牌超详细资料)

    全球九大知名轴承品牌超详细资料FAG公司概述▶FAG全称:FischerAktien-Gesellschaft费舍尔股份有限公司2001年被INA轴承公司收购,现隶属于德国舍弗勒集团(Schaeffler)总部所在地:德国巴伐利亚。

  • 姜小果扮演者(二十不惑中姜小果的饰演者是谁)

    姜小果扮演者《二十不惑》中姜小果的饰演者:卜冠今。卜冠今,毕业于中央戏剧学院表演系本科,2016年,因在《驴得水》中饰演孙佳而进入娱乐圈,相继参演了《那一场呼啸而过的青春》《消失的嫌疑人》《路不可急》《刺局》等。

  • 懒得废话的句子(懒得废话的句字有哪些)

    以下内容大家不妨参考一二希望能帮到您!懒得废话的句子非常非常讨厌社交了,一句废话都不想说,一个废字都不想打,尤其讨厌没有意义的寒暄。领导评价我的工作:沟通效率高,没有一句废话。不善言谈,不爱社交,不想说废话!我是个最讨厌听也从来不说废话的人,今天废话有点多了,本来是不想说的。

  • 其实我不叫这个!名字容易被叫错的史诗整理

    同理还有修罗之戮什么的读错lu而不是chuo啦2、巴恩的飓风短剑这个读作jùfēng不读旋xuan风也不读大da风其实这两个读音还可以理解啦但是米雪很难理解读作飚biao风的是什么心态!顺便米斯特汀是欧洲神话中引向灭绝的剑有兴趣的小伙伴们可以自行百度下ps.如果有兴趣的可以留言想了解的人多的话米雪可以整理下关于装备的神话故事5、怒叱狂龙臂铠这个读作nùchì狂龙臂铠之前米雪说这个字读chi的时候有小伙伴表示你骗人!

  • 炸盒子的做法和配方(炸盒子的烹饪方法)

    炸盒子的做法和配方材料:面粉1千克、猪肉0.6千克、水发海参0.2千克、虾仁0.2千克、玉兰片0.2千克、开水0.5千克、酱油、精盐、葱花、姜末、味精、香油、水淀粉、炸用油适量。将猪肉剁成茸,虾仁切成米粒大小的末,海参切成比黄豆稍大的丁;勺内加底油,把肉茸下勺炒至变色时投入虾仁、葱花、姜末、酱油、盐、炒熟后加入味精、海参,用水淀粉勾芡,淋上香油出锅,冷却待用。把盒子放入旺油锅内炸制,见盒鼓起呈金黄色即熟。