نمط الحالة
جزء من قسم البرمجة كائنية التوجه في رحلة Ruby على Coddy. الدرس 49 من 57.
ينقل نمط الحالة السلوك الذي يعتمد على الحالة الحالية لكائن ما إلى كائنات حالة منفصلة. يحتفظ الكائن الرئيسي، أي السياق، بحالة واحدة ويمرّر الاستدعاءات إليها؛ وتجيب الحالة وتقرر أي حالة تأتي بعدها:
class Red
def next_state
Green.new
end
def to_s
"red"
end
end
class Green
def next_state
Yellow.new
end
def to_s
"green"
end
end
class Yellow
def next_state
Red.new
end
def to_s
"yellow"
end
end
class TrafficLight
def initialize
@state = Red.new
end
def change
@state = @state.next_state
self
end
def to_s
"light is #{@state}"
end
end
light = TrafficLight.new
puts light
puts light.change
puts light.change.changeالناتج:
light is red
light is green
light is redمن دون النمط، تحتاج كل طريقة في السياق إلى case على قيمة الحالة، وتعني إضافة حالة جديدة تعديلها جميعًا. ومع كائنات الحالة، تكون كل حالة فئة واحدة تحتوي على قواعدها الخاصة:
# بدون النمط
def can_go?
case @status
when :red then false
when :green then true
when :yellow then false
end
end
# مع النمط
def can_go?
@state.can_go?
endيمكن للحالات رفض حدث لا يناسبها. هنا لا يمكن نشر المسودة مباشرةً؛ بل يجب أن تمر بالمراجعة أولًا:
class Draft
def submit
Review.new
end
def publish
raise ArgumentError, "cannot publish a draft"
end
def to_s
"draft"
end
end
class Review
def publish
Published.new
end
def to_s
"in review"
end
end
class Published
def to_s
"published"
end
end
state = Draft.new
begin
state.publish
rescue ArgumentError => e
puts e.message
end
state = state.submit
state = state.publish
puts stateالناتج:
cannot publish a draft
publishedيمكن لفئة أساسية مشتركة أن تمنح كل حالة الإجابة الافتراضية، مثل رفض كل حدث، بحيث تعرّف كل حالة الأحداث التي تقبلها فقط:
class State
def submit
raise ArgumentError, "cannot submit #{self}"
end
def approve
raise ArgumentError, "cannot approve #{self}"
end
end
class Review < State
def approve
Published.new
end
endالتحدي
سهلأكمل إشارة المرور. تحتوي الحالات Red وGreen وYellow كلٌّ منها على next_state (تنتقل الحمراء إلى الخضراء، والخضراء إلى الصفراء، والصفراء إلى الحمراء)، وcan_go? (الخضراء فقط) وto_s (اللون). تبدأ TrafficLight باللون الأحمر، وتنقل change إلى الحالة التالية، وتُرجع status القيمة red: stop أو green: go، وذلك بالاستعلام عن الحالة.
يقرأ الكود المُزوَّد الأوامر change أو status ويطبع الحالة بعد كل أمر.
ضع الكود الخاص بك في red.rb وgreen.rb وyellow.rb وtraffic_light.rb. يحتوي main.rb على كود الإدخال/الإخراج المُزوَّد، ولا يمكن تعديله.
جرّب بنفسك
require_relative 'red'
require_relative 'green'
require_relative 'yellow'
require_relative 'traffic_light'
# كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
input = []
while (line = gets)
input << line.chomp
end
light = TrafficLight.new
input.each do |cmd|
light.change if cmd == "change"
puts light.status
end
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتمتغيرات النسخةالأساليب و selfto_s و inspectمراجعة - بطاقة المكتبة7تعدد الأشكال والكتابة بأسلوب البطة
تعدد الأشكالالكتابة بأسلوب البطةالأساليب المجردةالحالات والفئاتمراجعة - طرق الدفع3أساليب ومتغيرات الأصناف
أساليب الأصنافمتغيرات كائنات الأصنافالثوابتأساليب الإنشاءمراجعة - رموز القسائمتدرّب بنفسك: مترجم Ruby عبر الإنترنت