كيفية تنفيذ الديكور مع المساواة غير المحلية؟
-
02-07-2019 - |
سؤال
تحياتي، أقوم حاليًا بإعادة بناء أحد برامجي، وقد وجدت مشكلة مثيرة للاهتمام.
لدي التحولات في أتمتة.التحولات دائما لها حالة البداية والحالة النهائية.تحتوي بعض التحولات على علامة ترمز إلى إجراء معين يجب تنفيذه عند الاجتياز.عدم وجود تسمية يعني عدم وجود إجراء.تحتوي بعض التحولات على شرط يجب استيفاؤه من أجل اجتياز هذا الشرط، إذا لم يكن هناك شرط، فإن الانتقال هو في الأساس انتقال إبسيلون في NFA وسيتم اجتيازه دون استهلاك رمز الإدخال.
أحتاج إلى العمليات التالية:
- تحقق مما إذا كان الانتقال يحتوي على تسمية
- الحصول على هذه التسمية
- إضافة تسمية إلى التحول
- تحقق مما إذا كان للانتقال شرط
- الحصول على هذا الشرط
- التحقق من المساواة
انطلاقًا من النقاط الخمس الأولى، يبدو هذا بمثابة ديكور واضح، مع انتقال أساسي واثنين من الديكورات:المسمى والحالة.ومع ذلك، فإن هذا النهج لديه مشكلة:يعتبر التحولان متساويين إذا كانت حالة البداية والحالة النهائية لهما هي نفسها، وكانت التسميات في كلا التحولين متساوية (أو غير موجودة) وكلا الشرطين متماثلان (أو غير موجودين).باستخدام الديكور، قد يكون لدي عمليتين انتقاليتين Labeled("foo"، Conditional("bar"، Transition("baz"، "qux"))) وConditional("bar"، Labeled("foo"، Transition("baz" "، "qux"))) التي تحتاج إلى مساواة غير محلية، أي أن المصممين سيحتاجون إلى جمع كل البيانات ويجب على الانتقال مقارنة هذه البيانات المجمعة على قاعدة مجموعة:
class Transition(object):
def __init__(self, start, end):
self.start = start
self.end = end
def get_label(self):
return None
def has_label(self):
return False
def collect_decorations(self, decorations):
return decorations
def internal_equality(self, my_decorations, other):
try:
return (self.start == other.start
and self.end == other.end
and my_decorations = other.collect_decorations())
def __eq__(self, other):
return self.internal_equality(self.collect_decorations({}), other)
class Labeled(object):
def __init__(self, label, base):
self.base = base
self.label = label
def has_label(self):
return True
def get_label(self):
return self.label
def collect_decorations(self, decorations):
assert 'label' not in decorations
decorations['label'] = self.label
return self.base.collect_decorations(decorations)
def __getattr__(self, attribute):
return self.base.__getattr(attribute)
هل هذا هو النهج النظيف؟هل فاتني شيء؟
أنا في حيرة من أمري، لأنني أستطيع حل هذه المشكلة - بأسماء فئات أطول - باستخدام الميراث التعاوني المتعدد:
class Transition(object):
def __init__(self, **kwargs):
# init is pythons MI-madness ;-)
super(Transition, self).__init__(**kwargs)
self.start = kwargs['start']
self.end = kwargs['end']
def get_label(self):
return None
def get_condition(self):
return None
def __eq__(self, other):
try:
return self.start == other.start and self.end == other.end
except AttributeError:
return False
class LabeledTransition(Transition):
def __init__(self, **kwargs):
super(LabeledTransition).__init__(**kwargs)
self.label = kwargs['label']
def get_label(self):
return self.label
def __eq__(self):
super_result = super(LabeledTransition, self).__eq__(other)
try:
return super_result and self.label == other.label
except AttributeError:
return False
class ConditionalTransition(Transition):
def __init__(self, **kwargs):
super(ConditionalTransition, self).__init__(**kwargs)
self.condition = kwargs['condition']
def get_condition(self):
return self.condition
def __eq__(self, other):
super_result = super(ConditionalTransition, self).__eq__(other)
try:
return super_result and self.condition = other.condition
except AttributeError:
return False
# ConditionalTransition about the same, with get_condition
class LabeledConditionalTransition(LabeledTransition, ConditionalTransition):
pass
يتصرف الفصل LabledConditionalTransition تمامًا كما هو متوقع - وعدم وجود رمز فيه أمر جذاب ولا أعتقد أن MI مربكًا بهذا الحجم.
بالطبع، سيكون الخيار الثالث هو دمج كل شيء في فئة انتقالية واحدة مع مجموعة من has_label/has_transition.
لذا...أنا في حيرة.هل فاتني شيء؟أي تنفيذ يبدو أفضل؟كيف يمكنك التعامل مع الحالات المشابهة، أي الكائنات التي تبدو وكأنها مصممة ديكور يمكنها التعامل معها، ولكن بعد ذلك، تظهر مثل هذه الطريقة غير المحلية؟
يحرر:تمت إضافة فئة الانتقال الشرطي.في الأساس، يتصرف هذا النوع مثل الديكور، مطروحًا منه الترتيب الذي تم إنشاؤه بواسطة ترتيب إنشاء الديكورات، ويتحقق الانتقال من صحة البداية والنهاية، وتتحقق فئة LabeledTransition من صحة التسمية، ويتحقق ConditionalTransition من صحة الشرط.
المحلول
أعتقد أنه من الواضح أنه لا أحد يفهم سؤالك حقًا.أود أن أقترح وضعه في السياق وجعله أقصر.على سبيل المثال، إليك أحد التطبيقات المحتملة لنمط الحالة في لغة بايثون، يرجى دراستها للحصول على فكرة.
class State(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
class Automaton(object):
def __init__(self, instance, start):
self._state = start
self.transitions = instance.transitions()
def get_state(self):
return self._state
def set_state(self, target):
transition = self.transitions.get((self.state, target))
if transition:
action, condition = transition
if condition:
if condition():
if action:
action()
self._state = target
else:
self._state = target
else:
self._state = target
state = property(get_state, set_state)
class Door(object):
open = State('open')
closed = State('closed')
def __init__(self, blocked=False):
self.blocked = blocked
def close(self):
print 'closing door'
def do_open(self):
print 'opening door'
def not_blocked(self):
return not self.blocked
def transitions(self):
return {
(self.open, self.closed):(self.close, self.not_blocked),
(self.closed, self.open):(self.do_open, self.not_blocked),
}
if __name__ == '__main__':
door = Door()
automaton = Automaton(door, door.open)
print 'door is', automaton.state
automaton.state = door.closed
print 'door is', automaton.state
automaton.state = door.open
print 'door is', automaton.state
door.blocked = True
automaton.state = door.closed
print 'door is', automaton.state
مخرجات هذا البرنامج ستكون:
door is open
closing door
door is closed
opening door
door is open
door is open
نصائح أخرى
من الكود الذي تم نشره، فإن الفرق الوحيد بين الانتقال والانتقال المسمى هو إرجاع get_lable() و has_label().في هذه الحالة، يمكنك ضغط هذين الفصلين في فئة واحدة تقوم بتعيين سمة التسمية على لا شيء و
return self.label is not None
في الدالة has_label().
هل يمكنك نشر الكود الخاص بـ ConditionalTransition
فصل؟أعتقد أن هذا سيجعل الأمر أكثر وضوحا.