新银河娱乐登入网址:预言需求——用好的设计,应对可能的变化

本文地址:http://www.ib776.com/geyunfei_hit/article/details/99297305
文章摘要:新银河娱乐登入网址,强大九阴真君 来吧想要把我们。

预言需求——用好的设计,应对可能的变化

新银河娱乐登入网址:楔子

认识了一位艺术家朋友,在他的引导下,开始看一些艺术展,看各种油画,水墨,水彩————屡屡为在那种固化颜料之下的展现的波光粼粼而赞叹不已。

在另一位朋友的安利下,我迷上音乐,沉迷古典。

在流连这些艺术中时,我总在不停的感叹:好的艺术,一定是不朽的,我们可以听20年前的流行,欣赏200年前的古典,欣赏百十年前的毕加索。

每有这些感慨,我总自惭形愧,作为软件工程师,代码总是暂时的,短暂的,甚至从写下的那一刻起,就是过时的。

我们甚至在今天通宵去写一个只在明天运行一次的脚本。

是的,悲观的角度看,我们一直在做无用功

于是,我总会想,如何写出’不朽’的代码,让自己的工作,尽可能的完美,尽可能延长他的运行周期。

对我来讲,这种方式,应该是预见需求,即预期在一个时间内,你接到的需求去如何的变化,当这种变化发生时,你的设计去如何的应对。

是的,想一个预言家一样,去给你的代码预知一段时间内的未来。

好的工程师,都应该是预言家

那么今天这篇,就从一个非常小的需求,聊聊我是怎么去做预言家,给代码卜卦。

需求

这是我在之前的东家接到的一个需求,当时我们用php的laravel框架已经实现了后台服务并预期上线。

因为我们本质上是一个理财的网站,刚上线时效果不是很好,于是PM说,我们要给新注册的用户发券,促进他们消费。

是的,我们的需求很简单,在用户注册时,给用户发券

也就是说,需求是这个样子:

第一次实现

在当时,我们已经有了auth/user/register接口,里面调用了userService这个类的一个newUser的方法,这个方法里实例化了一个userData,它生成了一个userModel,并把它加到数据库中。
大概是这个样子:

userControler/register
|-userService/newUser
|--userData/newUser
|---userModel/create
|----mysql ...

那么直观的解决方式
我们只要有一个coupon的实现(data/model) ,然后在userServicenewUser方法里调用newCoupon就可以了。

于时我们代码这个样子就可以:

userControler/register
|-userService/newUser
|--userData/newUser
|---userModel/create
|----mysql ...
|--couponData/newCoupon
|---couponModel/create
|----mysql ...

可是,这样真的可以了么?
这个需求,会有什么变化?

深挖需求

之前说过,我们的需求是在用户注册时,送消费券
这个需求,有两个关键点,即什么时间————用户注册,做什么事情————送消费券

那么,从时间行为两个维度考虑后继可能发生的变化:

  1. 时间问题
  • 只在用户注册时发券么?
  • 用户登录时会不会发券?
  • 用户购买的时候会发券么?
  • 用户充值的时候会发券么?
  1. 行为问题
  • 我们只会发券么?
  • 我们有没有可能发现金?(理财体验金,你懂的)
  • 我们有没有可能加入邀请返现?

也就是说,我们的需求,有可能变成这个样子:

在想到这些可能到来的变化后,我不得不重新审视自己的设计……

进一步的考虑

在发现我的需求可能的变化后,我开始考虑,怎么去应对未来的变化,那么我的设计的目的变成了:

  1. 以一种通用的方式实现送券;
  2. 用合适的方式获知用户注册这个时间点;
  3. 尽可能简单的把1和2串联到一起;

救星:观察者

在猜想需求变化时,我意外的发现,laravel 中的model是有观察者的,即你可以定向的观察某个model(mysql)中的操作:
像这样,先定义一个observer :

namespace App\Observers;
use App\User;
class UserObserver
{
    /**
     * Handle the User "created" event.
     * @param  \App\User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }
    /**
     * Handle the User "updated" event.
     * @param  \App\User  $user
     * @return void
     */
    public function updated(User $user)
    {
        //
    }

    /**
     * Handle the User "deleted" event.
     * @param  \App\User  $user
     * @return void
     */
    public function deleted(User $user)
    {
        //
    }
}

然后,在serviceProvider里注册这个:

namespace App\Providers;
use App\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     * @return void
     */
    public function register()
    {
        //
    }
    /**
     * Bootstrap any application services.
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
    }
}

这正是标准的观察者模式,并且,重要的一点,我们在php是可以不用类型传参的(或是在java里Object)之类,所以,我们的objectServer 变成了:

class CommmonObserver
{
    
    public function created($item)
    {
        //
    }
    public function updated($item)
    {
        //
    }

    public function deleted($item)
    {
        //
    }
}

实现: 时机的问题

有了laravel底层的observer,那么用观察者模式捕获用户注册这个时间点就方便了:

class ServiceProvider
{
    /**
     * Bootstrap any application services.
     * @return void
     */
    public function boot()
    {
        User::observe(CommonObserver::class);
    }
}

如果我们的CommonObserver只给user这一个model用,那么这部分可以到此为止了,但是我们希望再有类似问题,都可以用类似的方式处理,在这种方式下,变成了:

class CommmonObserver
{
    
    public function created($item)
    {
        raise_event($item,'created');
    }
    public function updated($item)
    {
        raise_event($item,'updated');
    }

    public function deleted($item)
    {
        raise_event($item,'deleted');
    }
}

raise_event中,我们这样处理:

function raise_event($item,$event){
    //getName 
    $model_name = get_class($item);
    //map to event ..
}

这时,我们可以定义一个类似的array:

return [
    "App\User"=>[
        "created"=>"userRegister"
    ],
    "App\UserLoginLog"=>[
        "created"=>"userLogin"
    ],
    // other event base model 
];

这样可以得到这个array后,在raise_event中去将具体的事件生成;
这时,我们的需求,受设计影响成为了这样:

实现: 行为的问题

我们解决了时机,那么行为就变得容易了。
根根上文,不难看出,我们在实现行为时可以得到三个参数:

  1. event ---- 我们定义的事件,比如userRegister
  2. db_operation ---- db的操作,比如update,create
  3. data_item ---- 对应的数据,比如user的实体。

注意一点,其实在进行后继业务处理时,我们不用去关注db_operation这个参数,因为其实event确定的话,db_operation就确定了。

因为我们不能只关注送券这一件事情,所以,我们要有一个约定(inteface)去承接相应的事件处理;

interface IEventHandler{
    function handle($event,$item);
}

然后可以实现一个AddCouponHandler:

class AddCouponHandler{
    public function handle($event,$item){
        //相关的操作
    }
}

那么,怎么关联到一起? 哈哈,嗯,如你所愿,我们再来个array:

return [
    "userRegister"=>[
        AddCouponHandler::class,
        //other handler
    ],
    "userLogin"=>[
        //other handler
    ],
    //
];

这样,我们的设计最终变成了这个样子:

理想主义的形式

我们在这个需求的第一版的迭代上,加入了这种设计,然后随着后继的迭代,我们又做了如下的更改:

  1. 对要发送的model进行处理,将db的原始数据进行裁剪,形成了统一的数据约定;
  2. 将event的处理变成了异步。

这时,我们的设计就成为了这种:

小结

我们将一个看似简单的需求————注册送券,无限的复杂化,去预测这个需求可能发生的迭代,可能产生的变化。
在这里,我们使用观察者模式,实现了对现有代码的扩展,同时,运用了大量的工厂模式(array).
在保证实现基础的基础上,我们做到了:

  1. 对原有代码实现了非侵入的扩展(user相关的内容没有更改)。
  2. 加入的所更改都是以增加为主;
  3. 新的业务逻辑是低耦合甚至完全解耦的。
  4. 为以后可能的变化留出了充足的时间。
展开阅读全文

Python数据分析与挖掘

01-08
92讲视频课+16大项目实战+源码+¥800元课程礼包+讲师社群1V1答疑+社群闭门分享会=99元   为什么学习数据分析?       人工智能、大数据时代有什么技能是可以运用在各种行业的?数据分析就是。       从海量数据中获得别人看不见的信息,创业者可以通过数据分析来优化产品,营销人员可以通过数据分析改进营销策略,产品经理可以通过数据分析洞察用户习惯,金融从业者可以通过数据分析规避投资风险,程序员可以通过数据分析进一步挖掘出数据价值,它和编程一样,本质上也是一个工具,通过数据来对现实事物进行分析和识别的能力。不管你从事什么行业,掌握了数据分析能力,往往在其岗位上更有竞争力。    本课程共包含五大模块: 一、先导篇: 通过分析数据分析师的一天,让学员了解全面了解成为一个数据分析师的所有必修功法,对数据分析师不在迷惑。   二、基础篇: 围绕Python基础语法介绍、数据预处理、数据可视化以及数据分析与挖掘......这些核心技能模块展开,帮助你快速而全面的掌握和了解成为一个数据分析师的所有必修功法。   三、数据采集篇: 通过网络爬虫实战解决数据分析的必经之路:数据从何来的问题,讲解常见的爬虫套路并利用三大实战帮助学员扎实数据采集能力,避免没有数据可分析的尴尬。   四、分析工具篇: 讲解数据分析避不开的科学计算库Numpy、数据分析工具Pandas及常见可视化工具Matplotlib。   五、算法篇: 算法是数据分析的精华,课程精选10大算法,包括分类、聚类、预测3大类型,每个算法都从原理和案例两个角度学习,让你不仅能用起来,了解原理,还能知道为什么这么做。
??2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值
缅甸小勐拉赌场开户网上娱乐场 巴黎人MW电子开奖时刻表 赌博网站后台登入 新世纪DS太阳城开奖时刻表 大发888江苏骰宝(快3)彩票
葡京广西快乐十分开奖 女神国际皇家六合彩开奖时刻表 海立方快3开奖号历史 阿玛尼VR3分彩计划群大全 捕鱼达人官方网
神话广东11选5时时彩计划软件 伯爵2娱乐平台官方网 威尼斯人湖南快乐十分官方网 tt娱乐网 鸿利亚洲顶级娱乐城
hb农场现金登入 新世纪北京赛车(PK10)开奖时刻表 太阳城娱乐城官网 亚洲必赢娱乐城76 心博天下官网官方网