我目前正在重新设计Python中与加密货币项目相关的一些对象。在我的设计中,我倾向于在任何有意义的地方使用合成和依赖注入。
transaction
对象是一个数据结构,其字段可以拆分并与字符串连接在一起(序列化/反序列化)。在加密的世界中,存在这种数据结构的变体,其中可以以不同的顺序添加,移除或序列化字段。
我有基本的transaction
课程:
class CTransaction(object):
def __init__(self):
#Basics
self.nVersion = 1
self.vin = []
self.vout = []
self.nLockTime = 0
self.sha256 = None
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
self.vin = deser_vector(f, CTxIn)
self.vout = deser_vector(f, CTxOut)
self.nLockTime = struct.unpack("<I", f.read(4))[0]
self.sha256 = None
def serialize(self):
r = ""
r += struct.pack("<i", self.nVersion)
r += ser_vector(self.vin)
r += ser_vector(self.vout)
r += struct.pack("<I", self.nLockTime)
return r
此变体可以是支持消息的事务。我使用继承并添加其他消息字段。它只是在序列化过程中附加到末尾:
class CTransactionMessage(CTransaction):
def __init__(self, Tx_Message):
super(CTransactionMessage, self).__init__()
# Support for Transaction message is version 2
self.nVersion = 2
self.strTxComment = Tx_Message
def deserialize(self, f):
super(CTransactionMessage, self).deserialize(f)
self.strTxComment = deser_string(f)
def serialize(self):
r = super(CTransactionMessage, self).serialize()
r += ser_string(self.strTxComment)
return r
在另一种变体中,您可能有POS类型货币的交易。
class CPosTransaction(CTransaction):
def __init__(self, ntime):
super(CPosTransaction, self).__init__()
# POS blocks have an 'nTime' field
self.nTime = ntime
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
self.nTime = struct.unpack("<i", f.read(4))[0]
self.vin = deser_vector(f, CTxIn)
self.vout = deser_vector(f, CTxOut)
self.nLockTime = struct.unpack("<I", f.read(4))[0]
self.sha256 = None
def serialize(self):
r = ""
r += struct.pack("<i", self.nVersion)
r += struct.pack("<i", self.nTime)
r += ser_vector(self.vin)
r += ser_vector(self.vout)
r += struct.pack("<I", self.nLockTime)
return r
在POS情况下,必须重新定义serialize / deserialize方法,因为新字段被添加到中间的某个位置。
最后,您可以使用支持邮件的POS类型货币进行交易。
我可以复制很多代码并编写一个新类:
class CPosTransactionMessage(CTransaction):
def __init__(self, Tx_Message, ntime):
super(CPosTransactionMessage, self).__init__()
# Support for Transaction message is version 2
self.nVersion = 2
self.strTxComment = Tx_Message
# POS blocks have an 'nTime' field
self.nTime = ntime
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
self.nTime = struct.unpack("<i", f.read(4))[0]
self.vin = deser_vector(f, CTxIn)
self.vout = deser_vector(f, CTxOut)
self.nLockTime = struct.unpack("<I", f.read(4))[0]
self.sha256 = None
self.strTxComment = deser_string(f)
def serialize(self):
r = ""
r += struct.pack("<i", self.nVersion)
r += struct.pack("<i", self.nTime)
r += ser_vector(self.vin)
r += ser_vector(self.vout)
r += struct.pack("<I", self.nLockTime)
r += ser_string(self.strTxComment)
return r
或者我可以使用多重继承。 (注意:我不确定我是否正确这样做)
class CPosTransactionMessage(CPosTransaction, CTransactionMessage):
def __init__(self, Tx_Message, ntime):
CPosTransaction.__init__(self, ntime)
CTransactionMessage.__init__(self, Tx_Message)
def deserialize(self, f):
CPosTransaction.deserialize(self, f)
CTransactionMessage.deserialize(self, f)
def serialize(self):
r = CPosTransaction.serialize(self)
r += CTransactionMessage.serialize(self)
return r
我应该使用合成并将serialize / deserialize方法分成更多对象吗?或者我在思考/过度复杂化了吗?
答案 0 :(得分:0)
首先:super
是你的朋友,特别是如果你正在做菱形继承。
其次:考虑不这样做。 Python支持它,但是尽可能坚持使用mixin通常是个好主意。 所以在你的情况下,它将是:
class CTransaction(object):
def serialize(self)
"do stuff"
class PosMixin(object):
def serialize(self, *args, **kwargs):
super(PosMixin, self).serialize(*args, **kwargs)
# do my stuff
class AnotherMixin(object):
def serialize(self, *args, **kwargs):
super(AnotherMixin, self).serialize(*args, **kwargs)
# do some more stuff
class TransactionPos(CTransaction, PosMixin): pass
class TransactionAnotherPos(CTransaction, PosMixin, AnotherMixin): pass
另一种方法是手动注册回调,然后调用它们。这是你的依赖注入。但除非你在飞行中产生很多这些类的变化,否则没什么意义。
答案 1 :(得分:0)
如果序列化格式是免费的并且不严格依赖于数据结构(在您的示例中TxMessage
附加在末尾,而nTime
插入中间),您可以使用的是用于描述格式的DSL,然后在基类中编写通用代码,用于处理使用该配方的序列化/反序列化:
class CTransaction(object):
format = [('nVersion', 'i'),
('vin', 'v', CTxIn),
('vout', 'v', CTxOut),
('nLockTime', 'I')]
def __init__(self):
... your usual code ...
def deserialize(self, f):
for field in self.__class__.format:
setattr(self, field[0],
deserializers[field[1]](f, *field[1:]))
self.sha256 = None
def serialize(self):
res = ""
for field in self.__class__.format:
res += serializers[field[1]](getattr(self, field[0]),
*field[1:])
return res
使用这种方法,您永远不会重新实现serialize
/ deserialize
,例如CPosTransaction
类实现为
class CPosTransaction(CTransaction):
format = [('nVersion', 'i'),
('nTime', 'I'),
('vin', 'v', CTxIn),
('vout', 'v', CTxOut),
('nLockTime', 'I')]
def __init__(self, ntime):
...
和CPosTransactionMessage
实现为
class CPosTransactionMessage(CTransaction):
format = [('nVersion', 'i'),
('nTime', 'I'),
('vin', 'v', CTxIn),
('vout', 'v', CTxOut),
('nLockTime', 'I'),
('strTxComment', 's')]
def __init__(self, Tx_Message, ntime):
...
如果DRY非常重要,您甚至可以在导入时构建食谱
class CPosTransaction(CTransaction):
# Insert nTime after first field
format = (CTransaction.format[:1] +
[('nTime', 'I')] +
CTransaction.format[1:])
def __init__(self, ntime):
...
class CPosTransactionMessage(CPosTransaction):
# Append strTxComment at the end
format = (CPosTransaction.format +
[('strTxComment', 's')])
def __init__(self, Tx_Message, ntime):
...
但是当然这会让你在阅读时更难理解代码。