标签 博客 下的文章

雨中游三坊七巷

连续多个星期都没有休息了,身体倒还可以,但是心情却有些烦躁。恰好今天事情不多,就和领导请示了一下,和同事出去散散心。来福州多次了,每次都是在客户现场和酒店两点一线间忙碌,还从未有时间游览过福州的景点。因为只有一下午时间,所以我们选择了一条常规路线:三坊七巷 – 乌山。

近两天福州降温,外面温度也就10度左右,天上还飘着蒙蒙细雨,心想:雨中的古街也许更有魅力。我们住在桥南,坐77路公交到双抛桥车站下车(市内出游我向来都首选公交),下车后向西走,不远处就可以看到南后街的路标,这里就是著名的三坊七巷的入口了。


南后街

南后街就是一条仿古步行街,也许“仿古”二字并不恰当,因为其身后的三坊七巷的确都有着很长年头了,但街路两旁矗立的带有明显现代人建造痕迹的仿古建筑还是给游客一种“仿”的感觉。和全国所以其他类似的街道一样,这些建筑已经全部被商家占领了^_^,向游客提供各种琳琅满目的商品。

我们下车所在的双抛桥车站位于杨桥路上,杨桥路未改造为大马路之前原名杨桥巷,也是三坊七巷中的七巷之一;由北向南,我们首先看到的是左手边的“郎官巷”。走入巷内映入眼帘的满是白墙、青瓦、石板路和木门结构的建筑,特别是走在雨后的石板路上别有一番味道。不过这里似乎正在做改造,巷子中有很多正在施工的痕迹,二梅书屋并未开放(是不是从来就没有开放过不得而知),严复的故居倒是可以游览。

老巷子1

老巷子2

回到南后街上继续向南走,路旁一家号称“中华老字号”、“福州第一家茉莉花茶”的茶叶店吸引了我们。茉莉花茶起源于福州,福州的茉莉花茶闻名海内,很多同事都想在回家的时候带上些茶叶自己喝或者送给亲友,我们遂走入店内。店内人不多,据店员介绍这家店是福州茶厂的直销店,福州茶厂目前依旧是一家国营茶厂,历史悠久,品质绝对可靠。我们品了"雀舌尖",听店员讲解:一泡是水、二泡是茶,三泡四泡是精华。像这种"雀舌尖"七八泡后还是香气犹存,喝到口中回甘持久。同事喜好茶,于是雀舌尖、龙珠和大红袍都购了些,满载出店。

正值中午时分,肚腹饥饿,在南后街口的导游图上得知街上有永和鱼丸和同利肉燕。福州鱼丸吃过一次,但不是最正宗的,这次一定要尝尝。永和鱼丸号称老字号,店里人很多。叫了一碗6元钱的“福寿双全”。所谓“福寿双全”就是鳗鱼丸和鲨鱼丸混在一起的意思。和上次吃的鱼丸相比,永和鱼丸稍小一些,筋头儿偏小,馅儿不是那么油,总体来说很不错。但如果说一定要和其他鱼丸分个上下,这还真不好讲。


福寿双全


永和鱼丸


同利肉燕

下一个坊是衣锦坊,这个坊里面的"水榭戏台"确值得大家一看,绝对是三坊七巷中的精华了。水榭戏台坐落在一处院落中。这个院落也着实不小,游客可以参观的有前后两层厅房。不知为何我们参观的时候前厅布满喜气,似乎是刚刚办完喜事。


老宅子

戏台在宅子东侧院,在荷花池上方一座漂亮的亭子似的建筑就是古戏台,更让人叫绝的是观众席居然是二层楼,想当年这家宅子的主人还真是阔气。之所以是二层,景点管理人员说是为了男女有别。


水榭戏台

剩余的巷和坊(黄巷、安民巷、官巷、文儒坊)景致与此前的多大同小异,而且东侧的多个巷子因改造施工,景点大多无法游览。我们也未深入,倒是花了不少时间在根雕艺术展、剪纸艺术展上。


三坊七巷

最后的光禄坊和吉庇路已经改造成了马路,再加上前面的杨桥巷,所谓的三坊七巷实际上已经成为了“两坊五巷”了。

沿着南后街继续南行就是乌山方向,但是考虑时间估计已经不够了,我们就放弃了乌山计划,改为参观林则徐纪念馆。福州文化政治名人不少,但林则徐的地位应是数一数二的。从林则徐纪念馆的馆舍和规模来看也可以印证我的结论。林则徐纪念馆的规划很好,无需人工指引,游客也能一个不落的游览完全部展馆。而且该纪念馆有效的利用现代信息技术和声光电来布展,使展品更形象逼真,在我之前参观的名人纪念馆中无出其右者。


林则徐纪念馆

在外游览了五个小时,心情也舒畅了些。还有不到10天就是春节了,还是尽快把客户现场的事情了了,春节我可不想在福州过^_^。

iterator的C实现

这几天一直处于编码状态,也找回了一些对代码的良好感觉。

昨天晚上闲暇时翻阅“Head First设计模式”,当翻到迭代器模式时,突然有了想法:实现一个iterator。这几天编码时恰好也写了一个简单的带有遍历功能的小数据结构,不妨用iterator改造一下这个数据结构的遍历接口,看是否能成行。

迭代器模式较为简单,网上的文章也多得很,这里就不再贽述了,直接看实现思路和代码吧。

在迭代器模式中,有几个角色不得不说,一就是iterator本身,还有一个就是所谓的“容器类”,容器类三个字显得概念很大,这里不用之。我们换一种轻松的说法,就是带有遍历功能的一类数据结构吧,这里记为类型T。类型T千变万化,iterator则以不变应万变,提供一种在无需知道T内部实现行为前提下的对T实例内各元素的有序遍历的接口。

这样一来iterator的应用场景大致就应该是这样的:

T     *t;
T_item_t *ti;

// …
iterator *itor = T_iterator(t);   
       
for ( ; has_next(itor); ) {
        ti = (T_item_t*)get_next(itor);
        // …
}

iterator_free(itor);

这里我们使用了四个函数has_next, get_next、iterator_free和T_iterator。其中has_next、get_next和iterator_free是iterator提供的函数接口,T_iterator则是需要每个支持iterator的数据结构去实现的接口。

以下是iterator.h的主要代码片段:

/* iterator.h */

#ifndef _ITERATOR_H_
#define _ITERATOR_H_

enum {
        FALSE = 0,
        TRUE  = 1
};
typedef int bool; /* TRUE or FALSE */

typedef struct iterator iterator;

typedef bool (*HAS_NEXT_HOOK_FUNC)(void *collection_instance, void *collection_inner_itor);
typedef void* (*GET_NEXT_HOOK_FUNC)(void *collection_instance, void *collection_inner_itor);

/* 提供给T类型实现T_interator时使用 */
iterator*       iterator_new(void *collection_instance,
                             void *collection_inner_itor,
                             HAS_NEXT_HOOK_FUNC h,
                             GET_NEXT_HOOK_FUNC g);

bool            has_next(iterator *itor);
void*           get_next(iterator *itor);
void            iterator_free(iterator *itor);

#endif /* _ITERATOR_H_ */

iterator_new接口主要供类型T实现T_iterator接口时使用,目的是对类型T屏蔽iterator的内部结构实现;collection_instance指向T的实例;collection_inner_itor则是类型T内部实现的一个保存iterator状态的变量,每个类型T都应该有这样一个内部数据;两个callback函数则分别由类型T内部实现,在T_iterator实现中调用iterator_new时传入。iterator对T有一定的侵入性,这在C语言中似乎是不可避免的,即使在Java中支持iterator接口的类也需要提供一个creatIterator的public接口,另外实现iterator接口的iterator类也需要提供具体的get_next和has_next实现。

以下则是iterator.c的代码,没有太多值得多说的地方,相信大家都可以看懂^_^:

/* iterator.c */
struct iterator {
        void                    *collection_instance;
        void                    *collection_inner_itor;
        HAS_NEXT_HOOK_FUNC      _has_next;
        GET_NEXT_HOOK_FUNC      _get_next;
};

iterator*       iterator_new( void *collection_instance,
                void *collection_inner_itor,
                HAS_NEXT_HOOK_FUNC h,
                GET_NEXT_HOOK_FUNC g) {
    iterator        *itor   = NULL;

    itor    = calloc(1, sizeof(*itor));
    if (!itor) return NULL;

    itor->collection_instance       = collection_instance;
    itor->collection_inner_itor     = collection_inner_itor;
    itor->_has_next = h;
    itor->_get_next = g;

    return itor;
}

void    iterator_free(iterator *itor) {
        if (itor) {
                if (itor->collection_inner_itor) free(itor->collection_inner_itor);
                free(itor);
        }
}

bool    has_next(iterator *itor) {
        return itor->_has_next(itor->collection_instance, itor->collection_inner_itor);
}

void*   get_next(iterator *itor) {
        return itor->_get_next(itor->collection_instance, itor->collection_inner_itor);
}

有了iterator,我们再举一个支持iterator遍历的list的例子,这里就不列出全部代码了,仅将关键的接口实现放出:

/* x_list.c */
struct x_list_inner_itor {
        x_list_item_t *item;
};

static bool x_list_has_next(void *collection_instance, void *collection_inner_itor) {
        x_list_t *list = (x_list_t*) collection_instance;
        struct x_list_inner_itor *p = (struct x_list_inner_itor *)collection_inner_itor;
        x_list_item_t *item = p->item;

        return (X_LIST_NEXT(item) != X_LIST_DUMMY_HEAD(list));
}

static void* list_get_next(void *collection_instance, void *collection_inner_itor) {
        struct x_list_inner_itor *p = (struct x_list_inner_itor *)collection_inner_itor;
        x_list_item_t *item = p->item;

        p->item = X_LIST_NEXT(item);

        return p->item;
}

iterator* x_list_iterator(x_list_t *list) {
        struct x_list_inner_itor *p = NULL;
        p = calloc(sizeof(*p), 1);
        if (!p) return NULL;

        p->item = X_LIST_DUMMY_HEAD(list);

        return iterator_new(list,
                (void*)p,
                x_list_has_next,
                x_list_get_next);              
}

以上只是提供了iterator的C实现的一种思路,大家见仁见智吧。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats