第十篇:策略模式:网络小说的固定套路

来源:互联网 发布:chocobank网络剧照片 编辑:程序博客网 时间:2024/06/07 16:31

策略模式:网络小说的固定套路

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

近日小舅子让我推荐几本好看的玄幻小说,下好了发给他。

想当初我唐家三少、天蚕土豆、跳舞等网络作者的小说也没少看,便满口答应了。

百度一搜“唐家三少”,好家伙,几年不见又出了这么多新书,产量惊人啊!把这些小说简介一看,啧啧,还是那个 屌丝逆袭 套路啊。

知乎上唐家三少有人喷有人捧,但有几句说的比较中肯:

因为现在的读者很多都是学生,找部小说来看着激动一下,激动过后呢?再找小说来激动,就这样以此循环,虚度光阴。

也许不能全怪作者,写太好读者看不懂,小学生作文水平刚好能迎合绝大部分读者。

铁打的小说流水的读者,导致了当前网络小说的固定套路,作家只要把故事梗概提取出来,把主角名字、背景什么的一换,就又是一本新书。唉,竟无语凝噎。

这种情况用代码怎么实现呢,我们来试试。

作者:张拭心 http://blog.csdn.net/u011240877

代码实现“如何用固定套路写小说”

1.先定义一个故事梗概接口 Synopsis ,里面设定了主要情节:

  • 不幸的开始
  • 突然有天遇到神人/捡到神器
  • 以弱胜强,暂露光芒
  • 开挂似的升级超快
  • 组团刷怪九死一生(主角怎么也死不了)
  • 功成名就 + 妻妾成群
/** * 网络玄幻小说的故事梗概接口 * 固定的一些套路 * Created by zhangshixin on 8/27/2016. */public interface Synopsis {    /**     * 穷困潦倒的开始     */    void badStart();    /**     * 突然有天遇到神人/捡到神器,实力大涨     */    void adventure();    /**     * 在一场战斗中以弱胜强     */    void winABattle();    /**     * 从此飞速成长     */    void growFast();    /**     * 组团刷怪,经历九死一生(主角怎么也死不了)     */    void manyFights();    /**     * 最终功成名就,妻妾成群     */    void succeed();    /**     * 组合起来就是小说内容     */    void getContent();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

2.有了梗概剩下的就是填内容了,我们分别创建两个具体小说类 StoryA 、 StoryB:

故事 A ,跳舞的恶魔法则:

/** * 故事 A ,恶魔法则 * Created by zhangshixin on 8/27/2016. */public class StoryA implements Synopsis {    private String mName;    public StoryA(String name) {        mName = name;    }    @Override    public void badStart() {        System.out.println(mName + " 无故穿越,因为没有魔法能力,成为将军家的废物,不受待见。");    }    @Override    public void adventure() {        System.out.println(mName + " 因为意外来到恶魔岛,在恶魔岛上遇见了恶魔的仆人,获得了一直想要的使用魔法的能力");    }    @Override    public void winABattle() {        System.out.println(mName + " 协助辰皇子夺得了帝国的权力,成为郁金香公爵");    }    @Override    public void growFast() {        System.out.println(mName + " 先后在曾曾曾祖母、恶魔仆人、圣骑士、魔导师的帮助下飞速成长");    }    @Override    public void manyFights() {        System.out.println(mName + " 建立魔法学院和魔法学会,与魔法工会分庭抗礼。坐拥西北十万雄兵,歼灭西北军团,打退草原人,带领人类全族击退北方的异族军队。");    }    @Override    public void succeed() {        System.out.println(mName + " 娶了女皇为妻子,成为罗兰帝国的英雄。");    }    @Override    public void getContent() {        badStart();        adventure();        winABattle();        growFast();        manyFights();        succeed();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

故事 B ,萧鼎的诛仙,这个小说的文笔、情节中是我最喜欢的小说之一,但也是有一些固定套路:

/** * 故事 B ,诛仙 * Created by zhangshixin on 8/27/2016. */public class StoryB implements Synopsis {    private String mName;    public StoryB(String name) {        mName = name;    }    @Override    public void badStart() {        System.out.println(mName + " 全村被屠,投入青云七脉中人数最少的大竹峰。");    }    @Override    public void adventure() {        System.out.println(mName + " 在一次伐竹过程中,为追一只三眼灵猴,入青云山深处得到了烧火棍。");    }    @Override    public void winABattle() {        System.out.println(mName + " 在七脉会武中侥幸进了前 4,和陆雪琪等人一起万蝠古窟历练。");    }    @Override    public void growFast() {        System.out.println(mName + " 在魔教十年,深得鬼王器重和真传。");    }    @Override    public void manyFights() {        System.out.println(mName + " 经历无数战斗,先是为鬼王卖命,后来与鬼王大战。");    }    @Override    public void succeed() {        System.out.println("天地不仁,以万物为刍狗。 " + mName +" 最后成为最有资格拥有天书的人。");    }    @Override    public void getContent() {        badStart();        adventure();        winABattle();        growFast();        manyFights();        succeed();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

3.故事梗概、具体内容都有了,剩下的就是量产了,据悉 唐家三少 日产 7k 字,实在佩服:

/** * 写小说 * Created by zhangshixin on 8/28/2016. */public class WriteNovel {    private Synopsis mSynopsis;     //故事梗概    private String mMainActorName;  //主角名称    /**     * 梗概、内容都差不多确定后,换个名称就是另一部小说     * @param mainName     */    public WriteNovel(String mainName){        switch (mainName){            case "张小凡":                mSynopsis = new StoryB(mainName);                break;            case "杜维":                mSynopsis = new StoryA(mainName);                break;            default:                mSynopsis = new StoryB(mainName);                break;        }    }    /**     * 获取小说内容     */    public void getNovelDetail(){        mSynopsis.getContent();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

可以看到,我们 把小说内容的选择封装在了 WriteNovel 中,减少了客户端与 WriteNovel 的耦合,这样等我们要换小说的具体实现时,客户端不用修改代码。

4.客户端只要输入主角名称,就可以得到一部小说,比如写一部类似诛仙的小说,主角名称为张拭心

@Test    public void testGetNovelDetail() throws Exception {        WriteNovel writeNovel = new WriteNovel("张拭心");        writeNovel.getNovelDetail();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们可以把 WriteNovel 类中的 default 设置为 StoryB ,即 诛仙:

public WriteNovel(String mainName){        switch (mainName){            //...省略掉不关键的内容            default:                mSynopsis = new StoryB(mainName);                break;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里写图片描述

5.假如现在需求变了,要写一部穿越的小说,主角还是 张拭心,这时只需修改 WriteNovel 中的 default 设置为 StoryA ,即 恶魔法则 即可,客户端不需要修改

/**     * 梗概、内容都差不多确定后,换个名称就是另一部小说     * @param mainName     */    public WriteNovel(String mainName){        switch (mainName){            case "张小凡":                mSynopsis = new StoryB(mainName);                break;            case "杜维":                mSynopsis = new StoryA(mainName);                break;            default:                mSynopsis = new StoryA(mainName);                break;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这里写图片描述

代码总结

用一个 UML 图表示上述代码的关系:

这里写图片描述

我们将公共的情节提取到梗概接口 Synopsis 中,然后创建不同的故事类,写小说时WriteNovel 中有一个接口的引用,根据客户端传入主角名称创建不同的实现类。

可以发现,这其实就是把在客户端代码中的判断提取了出来,让客户端减少对具体实现的依赖,转向对接口依赖,不就是我们之前说的 设计模式六大原则: 老板是如何减轻负担的 – 依赖倒置原则 吗?

其实这就是传说中的 策略模式

策略模式 Strategy

策略模式封装了变化。

策略模式又叫算法簇模式。它定义了一系列的算法用来完成相同的工作。策略模式让算法独立于使用它的客户而独立变化。

– 大话设计模式

只要遇到很多 if-else 或者有很多 case 的 switch,就可以考虑使用策略模式了,将这些行为独立的封装起来,可以在公共类中消除条件语句。

在实践中,只要听到需要在不同情况下应用不同的业务,就可以考虑使用策略模式来封装这种变化的可能性。

备注

我们在 Android 编码过程中,其实也经常遇到策略模式,在了解什么是策略模式后,下一篇文章我们去看看 Android 中有哪些地方用到了策略模式

代码地址点这里

其他设计模式文章: 
动态代理:1 个经纪人如何代理 N 个明星 
代理模式:女朋友这么漂亮,你缺经纪人吗?

原创粉丝点击