2021年7月21日星期三

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

你还在到处 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 { @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@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 { @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 typ......

原文转载:http://www.shaoqun.com/a/890915.html

跨境电商:https://www.ikjzd.com/

汇通达:https://www.ikjzd.com/w/1758

mymall:https://www.ikjzd.com/w/1050

欧舒丹:https://www.ikjzd.com/w/1756


你还在到处new对象吗?单身狗:我没对象,new怎么了?new对象本身是没问题的,但也不能全部new关键字走天下,其实有更好的方式,合适的时候可以试试工厂模式,代码会更优雅。什么是工厂模式?顾名思义,工厂模式中的"工厂"指的是创建对象的工厂,它提供了一种创建对象的最佳方式,也就是工厂模式。工厂模式的好处是这些对象不需要暴露自身的创建过程,统一由工厂模式进行创建和提供,隐藏了创建
lastpass:https://www.ikjzd.com/w/846
旺店通:https://www.ikjzd.com/w/2390
太平山顶旅游超详细攻略(游玩路线+旅游景点+门票价格):http://www.30bags.com/a/424127.html
太平山顶游玩手册 - :http://www.30bags.com/a/406805.html
太行古村凉沟桥 不用进村就把你美呆了:http://www.30bags.com/a/224269.html
太行山区老乡的一句方言 让我误入山坳小村:达柯:http://www.30bags.com/a/223015.html
男人爱㖭女人下面 喜欢让人㖭我下面:http://lady.shaoqun.com/a/247874.html
学长将我抱到小树林要了我 被学长要到腿软:http://lady.shaoqun.com/m/a/247173.html
深圳美术馆需要预约吗:http://www.30bags.com/a/516175.html
深圳永远永远爱你音乐剧演出是什么时候:http://www.30bags.com/a/516176.html
又一大bug!亚马逊FBA入站费用上涨十倍以上:https://www.ikjzd.com/articles/146802
2017互联网流行语热播!还有什么我不知道的吗?:http://lady.shaoqun.com/a/427367.html