Мой код:
abstract class StateMachine {
protected string State { get; private set; }
protected abstract void OnWorking();
protected abstract void OnPrepare();
protected abstract void OnCancel();
public bool Prepare() {
if(State != null) {
return false;
}
State = "Preparing";
OnPrepare();
State = "Prepared";
return true;
}
public bool Start() {
if(State != "Prepared") {
return false;
}
State = "Working";
OnWorking();
State = "Done";
return true;
}
public bool Cancel() {
if(State != "Working" || State == "Done") {
return false;
}
OnCancel();
State = "Canceled";
return true;
}
}
class Downloader : StateMachine {
protected override void OnPrepare() {
Console.WriteLine("I am preparing.");
Thread.Sleep(1000);
}
protected override void OnWorking() {
Console.WriteLine("I am working.");
Thread.Sleep(1000);
}
protected override void OnCancel() {
Console.WriteLine("Let's cancel the operation!");
}
}
class Program {
static void Main(string[] args) {
Downloader downloader = new Downloader();
Parallel.Invoke(() => {
downloader.Prepare();
downloader.Start();
}, () => {
// Cancel while working
Thread.Sleep(1500);
downloader.Cancel();
});
}
}
Вывод будет:
I am preparing.
I am working.
Let's cancel the operation!
Сейчас я создаю класс StateMachine
, и он работает очень хорошо. Это позволяет подклассам вообще не заботиться о текущих состояниях, и это здорово, потому что обработка состояний процесса - огромная боль в голове.
Проблема в том, что ничто не может остановить подкласс (Downloader
) от вызова этих защищенных методов в базовом классе (StateMachine
) самостоятельно. Например, подкласс может иметь что-то вроде:
protected override void OnWorking(){
Console.WriteLine("I am working.");
Thread.Sleep(1000);
OnCancel();
OnPrepare();
}
Тогда результат будет:
I am preparing.
I am working.
Let's cancel the operation!
I am preparing.
Let's cancel the operation!
Что не ожидается с точки зрения StateMachine
.
Поэтому я пытаюсь запретить подклассу вызывать защищенные методы. Но я чувствую, что делаю странные вещи. Я не думаю, что C# OOP концепции позволят такое поведение.
Хотя я не хочу делать эти защищенные методы невидимыми из подкласса. Я больше о создании исключений, если подклассы делают это. Может быть, мне нужно добавить дополнительные логи c в базовом классе дескриптор этого. Но это может сделать код грязным.
Что бы вы сделали в этой ситуации? Я имею в виду, что может быть элегантным способом решить эту проблему?