第一次“码上掘金”,我是这么憋出来一份参赛作品。

443 阅读4分钟

我正在参加「码上掘金迎新年」编程比赛,详情请看:码上掘金迎新年

参赛之前

码上掘金终于有了后端场,让只会写后端代码的我跃跃欲试,想要大展一番手脚。结果一看奖品,远远没有上次“码上掘金编程挑战赛”的七万现金那么丰厚,于是浅浅安慰下自己,奖品不丰厚估计竞争难度也会小一些,凭借自己丰富的编程经验一定能至少获得一个参与奖吧。

苦苦寻觅灵感

俗话说的好,凡事开头难,这不在我下定决心参赛之后,就遇到了第一个难关,一腔热血难以挥发。开发过程中用到的工具不少,但是想要在码上掘金平台上较好的适配一下,在没有任何依赖包的情况下有点困难。也曾在Github之类的网站上搜看看有没有啥合适的工具我自己复刻一套,但是还是迷茫,感觉要么太难了,要么花里胡哨没啥实际用途。

踏破铁鞋无觅处

实在憋不出来了,又看了看示例的Model转化成JSON,心想就这, 有啥难的,看我搞出来一套将JSON转换成Model,还要支持多语言的,Java、Python、Go都支持,还要支持嵌套。就这样有了目标。然后就开始全力开搞。

艰难实现路

首先要决策用啥语言,尽管平时Java用的最6最熟练,但是考虑到原生的Java在不借助别人工具包的情况下有点鸡肋,最后还是选择了万金油的Python。Python天生强大,原生就支持处理JSON,我只需要在基础上改改将处理后的JSON生成对应的Model即可。

说干咱就干。吭哧吭哧的写出来了第一个版本。

import json

json_str = """
{
"stringP":"key1",
"booleanP":  true,
"doubleP": 1.1,
"intP":1,
"array": [{"a":"b"}],
"obj":{"a":"b"},
"a":null
}
"""
json_map = json.loads(json_str)
print(json_map)

print(type(json_map))
for i in json_map:
    print(type(json_map[i]))
    print(isinstance(json_map[i], int))

"""
java -> function_map
"""


class PropertyConvert:
    def __init__(self):
        self.name = "abstract"
        self.property_open = ""
        self.property_close = ""
        self.model_open = ""
        self.model_close = ""
        self.bool_str = ""
        self.int_str = ""
        self.float_str = ""
        self.str_str = ""
        self.dict_str = ""
        self.function_map = {bool: self.convert_bool,
                             int: self.convert_int,
                             float: self.convert_float,
                             str: self.convert_str,
                             list: self.convert_list,
                             dict: self.convert_dict,
                             type(None): self.convert_null}
        pass

    def convert(self, property_name, property_value) -> str:
        pass

    def convert_bool(self, property_name, property_value) -> str:
        pass

    def convert_int(self, property_name, property_value) -> str:
        pass

    def convert_float(self, property_name, property_value) -> str:
        pass

    def convert_str(self, property_name, property_value) -> str:
        pass

    def convert_list(self, property_name, property_value) -> str:
        pass

    def convert_dict(self, property_name, property_value) -> str:
        pass

    def convert_null(self, property_name, property_value) -> str:
        pass


class JavaPropertyConvert(PropertyConvert):
    def __init__(self):
        super().__init__()
        self.name = "abstract"
        self.property_open = ""
        self.property_close = ""
        self.model_start = ""
        self.model_end = ""
        pass

    def convert(self, property_name, property_value) -> str:

        def convert_bool(self, property_name, property_value) -> str:
            pass

    def convert_int(self, property_name, property_value) -> str:
        pass

    def convert_float(self, property_name, property_value) -> str:
        pass

    def convert_str(self, property_name, property_value) -> str:
        pass

    def convert_list(self, property_name, property_value) -> str:
        pass
    

    def convert_dict(self, property_name, property_value) -> str:
        pass

    def convert_null(self, property_name, property_value) -> str:
        pass

然后感觉有点不对劲,搞的太复杂了,我的理想目标应该是写一个抽象类用于转换各种属性,他们的子类改一改配置就能用,而不是把各项方法都重新实现一遍。于是有了第二个版本。

import json

json_str = """
{
    "a":"1"
}
"""
json_map = json.loads(json_str)
print(json_map)

print(type(json_map))
for i in json_map:
    print(type(json_map[i]))
    print(isinstance(json_map[i], int))

"""
java -> function_map
"""


class PropertyConvert:
    def __init__(self):
        self.name = "abstract"
        self.seq = "\n"
        self.property_open = ""
        self.property_close = ""
        self.model_open = ""
        self.model_close = ""
        self.bool_str = ""
        self.int_str = ""
        self.float_str = ""
        self.str_str = ""
        self.dict_str = ""
        self.null_str = ""
        self.function_map = {bool: self.convert_bool,
                             int: self.convert_int,
                             float: self.convert_float,
                             str: self.convert_str,
                             list: self.convert_list,
                             dict: self.convert_dict,
                             type(None): self.convert_null}
        pass

    def convert(self, json_obj: dict) -> str:
        res = self.model_open + self.seq
        for property_name in json_obj:
            property_value = json_obj[property_name]
            res += self.function_map[type(property_value)](property_name, property_value) + self.seq
        return res + self.model_close + self.seq

    def convert_bool(self, property_name, property_value) -> str:
        return self.property_open + self.bool_str + property_name + self.property_close

    def convert_int(self, property_name, property_value) -> str:
        return self.property_open + self.int_str + property_name + self.property_close

    def convert_float(self, property_name, property_value) -> str:
        return self.property_open + self.float_str + property_name + self.property_close

    def convert_str(self, property_name, property_value) -> str:
        return self.property_open + self.str_str + property_name + self.property_close

    def convert_list(self, property_name, property_value) -> str:
        return self.property_open + self.str_str + property_name + self.property_close

    def convert_dict(self, property_name, property_value) -> str:
        return self.property_open + self.dict_str + property_name + self.property_close

    def convert_null(self, property_name, property_value) -> str:
        return self.property_open + self.null_str + property_name + self.property_close


class JavaPropertyConvert(PropertyConvert):
    def __init__(self):
        super().__init__()
        self.name = "Java"
        self.property_open = "class Model {"
        self.property_close = " }" + self.seq
        self.model_open = " "
        self.model_close = " "
        self.bool_str = "Boolean "
        self.int_str = "Integer "
        self.float_str = "Double "
        self.str_str = "String "
        self.dict_str = "Object "
        self.list_str = "List "
        self.null_str = "Object "



java_convert = JavaPropertyConvert()
res = java_convert.convert(json_map)
print(res)

算是能简单的支持Java了,但是我想做的更多,我还想要支持多语言,支持生成嵌套,怎么在这个基础上改呢。

import json

json_str = """
{
    "a":"1",
    "b":true,
    "c":1,
    "d":1.1,
    "e":[],
    "f":{},
    "g":null
}
"""
json_map = json.loads(json_str)
print(json_map)

print(type(json_map))
for i in json_map:
    print(type(json_map[i]))
    print(isinstance(json_map[i], int))

"""
java -> function_map
"""


class PropertyConvert:
    def __init__(self, seq=None
                 , property_open=None
                 , property_mid=None
                 , property_close=None
                 , model_open=None
                 , model_close=None
                 , bool_str=None
                 , int_str=None
                 , float_str=None
                 , str_str=None
                 , dict_str=None
                 , list_str=None
                 , null_str=None):
        self.name = "abstract"
        self.seq = seq
        self.property_open = property_open
        self.property_mid = property_mid
        self.property_close = property_close
        self.model_open = model_open
        self.model_close = model_close
        self.bool_str = bool_str
        self.int_str = int_str
        self.float_str = float_str
        self.str_str = str_str
        self.dict_str = dict_str
        self.list_str = list_str
        self.null_str = null_str
        self.property_str_map = {bool: self.bool_str,
                                 int: self.int_str,
                                 float: self.float_str,
                                 str: self.str_str,
                                 list: self.list_str,
                                 dict: self.dict_str,
                                 type(None): self.null_str}
        pass

    def convert(self, json_obj: dict) -> str:
        res = self.model_open + self.seq
        for property_name in json_obj:
            property_value = json_obj[property_name]
            res += self.convert_base(property_name, property_value)
        return res + self.model_close + self.seq

    def convert_base(self, property_name, property_value):
        return self.property_open + self.property_str_map[
            type(property_value)] + self.property_mid + property_name + self.property_close


class PythonPropertyConvert(PropertyConvert):
    def __init__(self):
        super().__init__(seq="\n", model_open="class Model:\n\tdef __init(self):",
                         model_close="",
                         property_open="\t\tself." ,
                         property_close=" = None\n",
                         property_mid="",
                         bool_str="",
                         int_str="",
                         float_str="",
                         str_str="",
                         dict_str="",
                         list_str="",
                         null_str="")


class JavaPropertyConvert(PropertyConvert):
    def __init__(self):
        super().__init__(
            seq="\n",
            model_open="Class Model {",
            model_close="}",
            property_open="\t",
            property_close=";\n",
            property_mid="\t",
            bool_str="Boolean",
            int_str="Integer",
            float_str="Double",
            str_str="String",
            dict_str="Object",
            list_str="List",
            null_str="Object")


class GoPropertyConvert(PropertyConvert):
    def __init__(self):
        super().__init__(
            seq="\n",
            model_open="type Model struct {",
            model_close="}",
            property_open="\t",
            property_close=";\n",
            property_mid="\t",
            bool_str="bool",
            int_str="int",
            float_str="float64",
            str_str="string",
            dict_str="interface{}",
            list_str="[]interface{}",
            null_str="interface{}")

    def convert_base(self, property_name, property_value):
        return self.property_open + property_name + self.property_mid + self.property_str_map[
            type(property_value)] + self.property_close


java_convert = JavaPropertyConvert()
go_convert = GoPropertyConvert()
python_convert = PythonPropertyConvert()
res = java_convert.convert(json_map)
print(res)
res = go_convert.convert(json_map)
print(res)
res = python_convert.convert(json_map)
print(res)

得益于良好的设计,对于Python和Go的支持很容易就实现了。但是呢,我还有一个宏伟的目标没有实现,就是想要优雅的支持嵌套,感觉这样才足够牛逼。于是在掉了几根头发之后,终于有了最后的成品。

各位掘友走过路过帮忙给点个赞。

参赛感悟

纸上得来终觉浅,绝知此事要躬行。有些东东看着很简单,想着也很简单,但是想把它做出来做完美,还是非常需要时间精力的。但是做出来的那一刻,成就感满满的。 本来两个星期之前 这篇文章就该发出来了,可是我阳了,导致今天才恢复了一点点精力,犹豫蓄力最终是把这篇文章也给憋出来了,希望我的经验可以帮助到大家。