我正在参加「码上掘金迎新年」编程比赛,详情请看:码上掘金迎新年
参赛之前
码上掘金终于有了后端场,让只会写后端代码的我跃跃欲试,想要大展一番手脚。结果一看奖品,远远没有上次“码上掘金编程挑战赛”的七万现金那么丰厚,于是浅浅安慰下自己,奖品不丰厚估计竞争难度也会小一些,凭借自己丰富的编程经验一定能至少获得一个参与奖吧。
苦苦寻觅灵感
俗话说的好,凡事开头难,这不在我下定决心参赛之后,就遇到了第一个难关,一腔热血难以挥发。开发过程中用到的工具不少,但是想要在码上掘金平台上较好的适配一下,在没有任何依赖包的情况下有点困难。也曾在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的支持很容易就实现了。但是呢,我还有一个宏伟的目标没有实现,就是想要优雅的支持嵌套,感觉这样才足够牛逼。于是在掉了几根头发之后,终于有了最后的成品。
各位掘友走过路过帮忙给点个赞。
参赛感悟
纸上得来终觉浅,绝知此事要躬行。有些东东看着很简单,想着也很简单,但是想把它做出来做完美,还是非常需要时间精力的。但是做出来的那一刻,成就感满满的。 本来两个星期之前 这篇文章就该发出来了,可是我阳了,导致今天才恢复了一点点精力,犹豫蓄力最终是把这篇文章也给憋出来了,希望我的经验可以帮助到大家。