脚本宝典收集整理的这篇文章主要介绍了设计模式(三):生成器模式,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
之前两篇的阅读效果不是很好,我一度怀疑这种题材的文章不受大家欢迎,直到前两天我面试了一个小姐姐...
面试过程中和小姐姐聊起她在上家公司做过的项目,其中有一个功能,根据小姐姐的描述,我第一感觉应该用生成器模式来实现
小姐姐说她并没有用生成器模式,就是简单的硬编码
我问她为什么不使用生成器模式实现的时候,小姐姐的一句话突破了我的认知下线
小姐姐说:我不知道什么是生成器模式,我不打算做架构师,没必要学设计模式
原来她认为设计模式只有在做架构设计的时候才会用到,跟普通程序员没有关系
我觉得小姐姐的观点存在严重问题,设计模式是程序员的基本技能,每个程序员都应该掌握并灵活应用
良好的代码设计不仅可以让代码重复性更高,还能使代码更易读从而降低代码后期的维护成本,最重要的是可以提高系统的可靠性
今天,我们就使用生成器模式来实现小姐姐的需求
我们先来看一下这个小姐姐的项目的具体需求
根据用户近期的消费金额、消费次数、浏览商品类型、商品价格区间等一些属性,生成用户画像。根据画像分析用户行为,实现精准营销或刺激消费等。
当然,不同的业务关注的角度也不同。比如精准营销业务关注的是用户近半年的数据,而且以消费数据为主;刺激消费业务关注的是用户近一个月的数据,而且以常打开的商品为主
从编程角度把需求提炼一下,大概就是以下两点:
我们先来看一下小姐姐当初是怎么实现这个需求的
小姐姐的代码是在精准营销和刺激消费的业务逻辑里面,分别创建了一个User对象。
两个业务中创建User对象的逻辑基本一样,只有在获取近期消费数据时稍有差别。一个是获取近半年的数据,另一个是获取近一个月的数据
这样的硬编码是把User对象的创建过程,嵌入到了其他业务逻辑里面,这就造成一些问题
User对象的创建逻辑基本一样,但是写了两遍。如果后期加入新的业务,User对象的创建逻辑还要再写一遍,代码重用性太低
示例中的伪代码模拟的比较简单,实际上User对象的创建过程非常复杂,需要查询各种数据并且对数据进行过滤、分类、整理,代码可能有几百行
精准营销或刺激消费的业务逻辑也是非常复杂的,把两块复杂的逻辑写到一块,后期阅读或维护代码的成本将几何倍的增长
将两块业务逻辑写到一起,其中不免会共享一些逻辑。
如果后期想对共享的逻辑进行修改,让其仅对其中一方生效,代码的修改是很不友好的,很容易造成另一方的逻辑漏洞
我们可以尝试使用生成器模式来解决这些问题
生成器模式是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
换成大白话理解就是:一个复杂的对象,它的创建过程和使用过程要分开。对于对象的使用者来说,我只需要告诉创建者我需要使用这个复杂对象,至于这个复杂对象是怎么创建的,不关我事 (ps:有点渣男的味道)
在创建一个对象时,同时满足以下条件,可以使用生成器模式
如果需要创建的对象不复杂,这时候是没必要使用生成器模式的。因为生成器模式本身的代码实现有一点复杂,使用它成本有点高,还不如简单的硬编码
如果对象的创建步骤不固定,也不推荐使用生成器模式。
假如在小姐姐的项目中,如果精准营销需要用户的消费数据,不需要浏览商品数据;刺激消费需要用户的浏览商品数据,不需要消费数据。
User对象的创建步骤就是
两个业务创建User对象的步骤是不一样的,这时候不适合使用生成器模式
如果所有的调用者需要的对象完全一样,也不需要使用生成器模式。
假如小姐姐的需求中,两个业务关注的消费数据都是近一个月的,对消费数据和商品数据的关注度也是一样的,就不需要使用生成器模式,只需要把User对象的创建过程进行单独的封装,两个业务直接调用即可
我们先来看一下生成器模式的架构
套用到我们需求中,User
对象的创建就是下面这个样子
下面使用代码实现小姐姐的需求,首先定义我们要创建的对象,也就是 User
类
public class User { PRivate String nickname; private int payCnt; private int payAmt; private List<String> productTyPE; private List<String> amtInterval; public void setNickname(String nickname) { this.nickname = nickname; } public void setPayCnt(int payCnt) { this.payCnt = payCnt; } public void setPayAmt(int payAmt) { this.payAmt = payAmt; } public void setProductType(List<String> productType) { this.productType = productType; } public void setAmtInterval(List<String> amtInterval) { this.amtInterval = amtInterval; }}
第二步,编写构造接口定义创建 User
对象需要的步骤,并提供返回 User
对象的方法
public interface IUserBuilder { // 构建用户昵称 String buildNicaname(); // 构建用户消费次数,days代表最近天数 int buildPayCnt(); // 构建用户消费金额,days代表最近天数 int buildPayAmt(); // 构建用户经常浏览商品类型 List<String> buildProductType(); // 构建用户经常浏览商品价格区间 List<String> buildAmtInterval(); // 获取user对象 User getUser();}
第三步,编写构造接口的具体实现类,重写每一个方法,编写每一个方法的具体实现逻辑。
public class UserBuilder implements IUserBuilder { private String days; public UserBuilder(String days) { this.days = days; } @override public String buildNicaname() { String nicaname = "赫连小伍"; System.out.println("查询用户昵称为:" + nicaname); return nicaname; } @Override public int buildPayCnt() { int payCnt = 0; if ("30".equals(days)) { payCnt = 1; } else{ payCnt = 10; } System.out.println("查询用户近" + days + "天的消费笔数为:" + payCnt); return payCnt; } @Override public int buildPayAmt() { int payAmt = 0; if ("30".equals(days)) { payAmt = 2; } else{ payAmt = 100; } System.out.println("查询用户近" + days + "天的消费金额为:" + payAmt); return payAmt; } @Override public List<String> buildProductType() { List<String> list = new ArrayList<>(); list.add("增发剂"); list.add("格子衫"); System.out.println("查询用户浏览的商品类型为:" + list); return list; } @Override public List<String> buildAmtInterval() { List<String> list = new ArrayList<>(); list.add("1-9"); list.add("2-10"); System.out.println("查询用户浏览的商品价格区间为:" + list); return list; } @Override public User getUser() { User user = new User(); user.setNickname(this.buildNicaname()); user.setPayCnt(this.buildPayCnt()); user.setPayAmt(this.buildPayAmt()); user.setProductType(this.buildProductType()); user.setAmtInterval(this.buildAmtInterval()); return user; }}
第四步,编写 Director
类,对精准营销和刺激消费两块业务分别提供对应的获取 User
的方法。这里为了方便调用,方法全部采用 static
的
public class Director { // 为精准营销提供获取User的方法 public static User getJzyxUser() { IUserBuilder userBuilder = new UserBuilder("360"); return userBuilder.getUser(); } // 为刺激消费提供获取User的方法 public static User getCjxfuser() { IUserBuilder userBuilder = new UserBuilder("30"); return userBuilder.getUser(); }}
最后一步,模拟精准营销和刺激消费的业务,分别获取对应的 User
对象
public static void main(String[] args) { // 模拟精准营销业务逻辑 User jzyxUser = Director.getJzyxUser(); System.out.println("精准营销获得的User对象为:" + jzyxUser); System.out.println("开始精准营销的业务逻辑"); // 模拟刺激消费业务逻辑 User cjxfUser = Director.getCjxfUser(); System.out.println("刺激消费获得的User对象为:" + cjxfUser); System.out.println("开始刺激消费的业务逻辑");}
这就用生成器模式实现了小姐姐的需求
对于精准营销或刺激消费的业务逻辑来说,它们不用再关心 User
对象的创建过程,可以更专注于自身的业务逻辑,无论是代码阅读或后期维护都更方便
生成器模式也被称作创建者模式或建造者模式,它属于设计模式三大类型中的创建型模式
与工厂模式相比,生成器模式更善于处理创建步骤固定的复杂对象。它与工厂模式并没有很明显的界限,在许多设计初期,大部分程序员都习惯用工厂方法模式来构建代码,随着业务变得复杂,代码也会不断的重构。代码架构也逐渐的演变成抽象工厂模式、生成器模式
生成器模式也不能频繁的使用,如果项目的内部变化复杂,可能会导致需要定义很多具体生成器类来实现这种变化,导致系统变得很庞大
每一种设计模式都有利有弊,权衡利弊后找出适合自己项目的模式才会使代码变得更 “完美”
以上是脚本宝典为你收集整理的设计模式(三):生成器模式全部内容,希望文章能够帮你解决设计模式(三):生成器模式所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。