美文网首页
写点野路子代码

写点野路子代码

作者: 一个野路子程序员 | 来源:发表于2021-09-07 11:46 被阅读0次

前几天在某个微信群里,有小伙伴发了一个力扣上的编程题,很有意思。如下:

image
题目很简单,群里的小伙伴开始了讨论。有些历害的小伙伴给出了公式:
image
还有的写出了公式的推导过程:
image
还有一些手快的已经写出了代码:
image
代码很简洁,也实现了功能。
大家的讨论都是围绕如何实现展开的,题目本身也很简单。但是好像没有人关注这个题目中描述的场景,这是很多程序员的通病:只关注技术实现而忽略了业务本身。比如上面的代码如果不是看题目都不知道代码在表达什么。如果我再添加一个需求:每周五要出去玩,不存钱。这段代码可能就多了一个 if-else。如果再加一个需求:由于周 5 没存钱,为了快速达到目标,周三存两倍。那可能就又多出了一个 if-else。随着业务的不断迭代,代码就慢慢的变成了意大利面似的代码(祖传代码),传说中的屎山。

野路子写法

如果我来做这个题的话,拢共分三步。


image
  1. 整明白每周每天能存多少钱
  2. 整明白一共有多少周
  3. 利用上面的完成的工作,用总天数算出有多少周,再把每周每天的钱加起来就完成了

整明白每周每天能存多少钱

在写代码之前我一般会写一些草稿代码,然后不断调整。这样可以站在代码读者的角度或者调用者的角度来审视代码的最终效果。过程我就不说了,最后的结果是得到了一组测试

 @Test
    public void save_money_every_day_on_frist_week() {
        Week week = Week.of(1);

        assertThat(week.day(1).money()).isEqualTo(1);
        assertThat(week.day(2).money()).isEqualTo(2);
        assertThat(week.day(3).money()).isEqualTo(3);
        assertThat(week.day(4).money()).isEqualTo(4);
        assertThat(week.day(5).money()).isEqualTo(5);
        assertThat(week.day(6).money()).isEqualTo(6);
        assertThat(week.day(7).money()).isEqualTo(7);
    }

    @Test
    public void save_money_every_day_on_second_week() {
        Week week = Week.of(2);

        assertThat(week.day(1).money()).isEqualTo(2);
        assertThat(week.day(2).money()).isEqualTo(3);
        assertThat(week.day(3).money()).isEqualTo(4);
        assertThat(week.day(4).money()).isEqualTo(5);
        assertThat(week.day(5).money()).isEqualTo(6);
        assertThat(week.day(6).money()).isEqualTo(7);
        assertThat(week.day(7).money()).isEqualTo(8);
    }

    @Test
    public void save_money_every_day_on_third_week() {
        Week week = Week.of(3);

        assertThat(week.day(1).money()).isEqualTo(3);
        assertThat(week.day(2).money()).isEqualTo(4);
        assertThat(week.day(3).money()).isEqualTo(5);
        assertThat(week.day(4).money()).isEqualTo(6);
        assertThat(week.day(5).money()).isEqualTo(7);
        assertThat(week.day(6).money()).isEqualTo(8);
        assertThat(week.day(7).money()).isEqualTo(9);
    }

分别是第1周,第2周,第3周每天能存多少钱。代码中对这个概念进行了建模。现在实现代码还没有写,接下来就是实现了。

public class Week {
    private int whichWeek;

    public Week(int whichWeek) {
        this.whichWeek = whichWeek;
    }

    public static Week of(int whickWeek) {
        return new Week(whickWeek);
    }

    public DayOfWeek day(int day) {
        return DayOfWeek.of(this, day);
    }

    public int whichWeek() {
        return whichWeek;
    }
}
public class DayOfWeek {
    private final Week week;
    private final int whichDay;

    public DayOfWeek(Week week, int whichDay) {
        this.week = week;
        this.whichDay = whichDay;
    }

    public static DayOfWeek of(Week week, int day) {
        return new DayOfWeek(week, day);
    }

    public int money() {
        return week.whichWeek() - 1 + whichDay;
    }
}

整明白一共有多少周

先用一个测试来表达我想要的最终效果

 @Test
    public void should_create_week_from_given_days() {
        assertThat(Week.weeks(4)).isEqualTo(new Week[] {Week.of(1)});
        assertThat(Week.weeks(7)).isEqualTo(new Week[] {Week.of(1)});
        assertThat(Week.weeks(10)).isEqualTo(new Week[] {Week.of(1), Week.of(2)});
        assertThat(Week.weeks(20)).isEqualTo(new Week[] {Week.of(1), Week.of(2), Week.of(3)});
    }

实现

public class Week {
 
    public static Week[] weeks(int days) {
        int numberOfWeeks = days / 8 + 1;

        Week[] weeks = new Week[numberOfWeeks];

        for (int i = 0; i < numberOfWeeks; i++) {
            weeks[i] = of(i + 1);
        }

        return weeks;
    }

}

省略了equals方法

最后一步

还是先写测试

 @Test
    public void should_calucate_saved_money_given_days() {
        LeetCodeBank bank = new LeetCodeBank();

        assertThat(bank.howMuchMoneySaved(4)).isEqualTo(10);
        assertThat(bank.howMuchMoneySaved(10)).isEqualTo(37);
        assertThat(bank.howMuchMoneySaved(20)).isEqualTo(96);
    }

实现

public class LeetCodeBank {

    public static final int LAST_DAY_OF_WEEK = 8;

    public LeetCodeBank() {

    }

    public int howMuchMoneySaved(int days) {
        int totalMoney = 0;
        Week[] weeks = Week.weeks(days);

        int currentDayOfWeek = 1;
        int currentWeek = 0;

        for (int i = 0; i < days; i++) {
            totalMoney += weeks[currentWeek].day(currentDayOfWeek).money();

            currentDayOfWeek++;

            if (currentDayOfWeek == LAST_DAY_OF_WEEK) {
                currentDayOfWeek = 1;
                currentWeek++;
            }
        }

        return totalMoney;
    }
}

现在就实现完了。当然,还有一些边界值处理这里就不说了。有人可能会说,这个代码的空间复杂度和时间复杂度太高了吧!3行代码能写完的居然整出这么多类。代码的整个生命周期中大部分时间是在被阅读和修改,所以代码表达力强,易于阅读和修改,可能比所谓的“性能”更重要。想想工作中大部分时间是不是都在处理需求变化。上面的代码其实就是OOP而已,可能很多程序员还不能理解这种写代码的方式,毕竟大家用Transaction script模式比较多,这就引出了为什么很多程序员学习DDD,根本找不到门,因为面向对象都还没整明白,domain design就design了个寂寞。

相关文章

  • 写点野路子代码

    前几天在某个微信群里,有小伙伴发了一个力扣上的编程题,很有意思。如下: 题目很简单,群里的小伙伴开始了讨论。有些历...

  • 当野路子遇见野路子

    我觉得我路子就挺野的 不过这公司用人路子更野...我投的岗位叫“新媒体运营经理” ,这个词语的意思本来是出内容、寻...

  • 野路子

    不知道在你的生活中有没有在不停地寻找问题的最优解,却忽略拿起其中的一把锤子及时上路——检验这个解法的可行性。在寻找...

  • 野路子

    野路子 不骗你,每次我出场打球,都有粉丝在一旁呐喊助威,替我加油鼓劲,有些不了解我的,张大了嘴巴,瞪直了眼睛,满是...

  • 野路子

    感觉好好工作已经没办法冲破第一宇宙速度了 所以路子要野,心也不能正常运行,怎么特别怎么来 ,哈哈 千真万确,不要用...

  • 路子野

    相对于精神疲于奔命,身体 总留在原地烙物 ​圈地自萌与四体不勤 ​相称相知,在这个 用不着海王金樽的新年 “岁月静...

  • 野路子

    何为“野路子”?简言之,当一个人不墨守陈规,敢于另辟蹊径,就可以称之为野路子。由此可以看出,野路子应该是一个中性的...

  • 路子野

    相对于精神疲于奔命,身体 ​总会在原地烙物 ​圈地自萌与四体不勤 ​相称相知,在这个 用不着海王金樽的新年 ​“岁...

  • △/路子野

    路子野。我想是我对于自己的定义。 其实小学五年级以前,语文是没上过八十分的,作文也写的零零落落。 直到五年级那年换...

  • 野路子

    朋友学素描有板有眼,按老师要求备画具一应俱全,上课画作业按部就班,进步也是看得见。很佩服朋友,自己却没能做到。 这...

网友评论

      本文标题:写点野路子代码

      本文链接:https://www.haomeiwen.com/subject/rknuwltx.html