Witam
W ramach ćwiczeń m.in. z klasą String, próbuję napisać program do wprowadzania korekt w plikach programów maszyny.
W Skrócie - Program Maszyny:
- maszyna przyjmuje pliki tekstowe jako programy wsadowe,
- programy tej maszyny używaja około 30 różnych rozkazów,
- rozkazy jeżeli chodzi o składnię róznią sie typem rozkazu (string) liczbą parametrów (int lub decimal) umieszczonych za rozkazem rozdzielonych spacjami
- w linii każdego rozkazu po średniku może być dowolny komentarz
przykladowo wyglada on tak:
BEGIN
; HOME 0
OFF 40 ;osl. G
; WAITON 06 ;czek. osl. G
WAITON 00 ;czek. zac. G
nop 0.1
MOVA 94.30 52.50 46.00 80;nad korek OK z=45
MOVA 94.30 51.30 46.70 30
MOVA 95.00 49.00 46.50 50;w prawo i PRZOD
MOVE -40 00.00 00.00 00.50 100
move -25; 30 ;25
MOVE -140 0.70 0.00 0.00;
; on 45
OFF 47 ;zaciski D
WAITON 01 ;czek. D
NOP 00.20
MOVA 93.0 35.80 46.90 100;
HOME 00
OFF 55 ;licznik
END.
Moje wymagania Dla programu:
Przypadek gdy maszyna się psuje, idzie do serwisu, wraca juz sprawna ale ma przesunięcie w osi X o 1,5mm (osie ruchów X, Y, Z - i w tych osiach takie przesuniecia sie zdarzaja). Rozkazy które korzystają z osi X, Y, Z to MOVE i MOVA. Chciałbym w całym programie wprowadzać offset w wybranej osi ruchów (czyli w tych rozkazach MOVE i MOVA, rozkaz MOVE jest "przeciazony" i moze miec różna ilosc parametrów).
poza tym chciałbym jako opcję dodac "Porządkowanie/Standaryzowanie kodu programu". tzn. wszystkie rozkazy pisane sa tylko wielkimi literami, parametry przyjmuja ten sam ujednolicony format, parametry rozkazów wystepują zawsze na tej samej pozycji w linii, komentarz jeżeli jest to zaczyna się zawsze na tej samej pozycji w linii, jeżeli linia zaczyna się od ";" to nic z nią nie robić ale mam mieć możliwość usunięcia takich martwych linii, dla powyzszego przykładu wygladałoby to mniej więcej tak:
BEGIN
; HOME 0
OFF 40 ;osl. G
; WAITON 06 ;czek. osl. G
WAITON 00 ;czek. zac. G
NOP 00.10
MOVA 94.30 52.50 46.00 80 ;nad korek OK z=45
MOVA 94.30 51.30 46.70 30
MOVA 95.00 49.00 46.50 50 ;w prawo i PRZOD
MOVE -40.00 00.00 00.00 00.50 100
MOVE -25.00 ; 30 ;25
MOVE -140.00 00.70 00.00 00.00;
; on 45
OFF 47 ;zaciski D
WAITON 01 ;czek. D
NOP 00.20
MOVA 93.00 35.80 46.90 100;
HOME 00
OFF 55 ;licznik
END.
Wstępnie wymyśliłem taki rozkład klas dla tego programu:
Klasa całego programu:
class ProgramMaszyny
{
private List<LiniaProgramu> poszczegolneLinieProgramu;
public string NazwaProgramu { get; private set; }
public ProgramMaszyny(string initNazwa)
{
poszczegolneLinieProgramu = new List<LiniaProgramu>();
NazwaProgramu = initNazwa;
}
public int PobierzIloscLinii()
{
return poszczegolneLinieProgramu.Count;
}
public string PobierzLinieProgramu(int index)
{
return poszczegolneLinieProgramu[index].ToString();
}
public void DodajLinieProgramu(string initLinia)
{
poszczegolneLinieProgramu.Add(new LiniaProgramu(initLinia));
}
Klasa jednej linii programu:
class LiniaProgramu
{
string czescRozkazowa;
string czescKomentarzowa;
public int PozycjaPoczatkuKomentarza { get; private set; }
//public int PozycjaPoczatkuRozkazu { get; private set; }
public LiniaProgramu(string init)
{
this.PozycjaPoczatkuKomentarza = init.IndexOf(";");
if (this.PozycjaPoczatkuKomentarza > 0)
{
czescRozkazowa = init.Remove(this.PozycjaPoczatkuKomentarza);
czescKomentarzowa = init.Remove(0, this.PozycjaPoczatkuKomentarza);
}
else
{
czescRozkazowa = init;
czescKomentarzowa = null;
}
}
public override string ToString()
{
return czescRozkazowa + czescKomentarzowa + "\n";
}
}
Wczytuję go tak:
private void btnOtworz_Click(object sender, EventArgs e)
{
StreamReader reader = null;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
if (openFileDialog1.OpenFile() != null)
{
using (reader = new StreamReader(openFileDialog1.FileName))
{
progMaszyny = new ProgramMaszyny(openFileDialog1.SafeFileName);
while (!reader.EndOfStream)
{
progMaszyny .DodajLinieProgramu(reader.ReadLine());
}
WyswietlProgram();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Problem z odczytaniem pliku.\nSzczegóły błędu:\n\n"
+ ex.Message);
progMaszyny = null;
}
}
}
private void WyswietlProgram()
{
richTextBoxPodgladProgramu.Clear();
labelNazwaOtwartegoProgramu.Text = "";
for (int i = 0; i < progMaszyny .PobierzIloscLinii(); i++)
{
richTextBoxPodgladProgramu.AppendText(progMaszyny.PobierzLinieProgramu(i));
}
labelNazwaOtwartegoProgramu.Text = progMaszyny.NazwaProgramu;
}
Wydaje mi się, że do rozwiązania swojego problemu mogę zastosować wzorzec Strategia, ale pewny nie jestem jak to zrobić i czy mogę bazowaćna tym co do tej pory zrobiłem.
Konkretnie w klasie LiniaProgramu, pola:
string czescRozkazowa;
string czescKomentarzowa;
chce zastąpić klasami o tych samych nazwach.
Moje pytania:
I tu zaczynam mieć problem z wyobrażeniem i zaplanowaniem sobie kolejnych warstw "obiektów w obiektach".
Chyba klasa **CzescRozkazowa **powinna być abstrakcyjna. Z niej dziedziczyłyby podklasy i tez nie wiem jakie (kazdy rozkaz jako klasa(30 podklas)?, grupa rozkazów ze względu na ilośc przyjmowanych parametrów (6 podklas)?)
Wg. Wzorca Strategia abstrakcyjna klasa CzescRozkazowa powinna zawierać pola InterfejsWprowadzeniaOffsetu i InterfejsUsystematyzowaniaSkladniRozkazu.
Te interfejsy byłyby implementowane przez klasy które byłyby "odpowiednikami?" klas dziedziczących z CzescRozkazowa i implementowałyby sposoby wprowadzania offstów albo porządkowania rozkazów?
Czy moglibyście mnie nakierować czy dobrze kombinuje z tym wzorcem Strategia, czy mam gdzies jakis błąd w rozumowaniu? I ogólnie czy ten podział na klasy Program, LiniaProgramu jest ok czy to jakoś inaczej trzeba zrobić?
Szczególnie interesuje mnie - zakładając że do tej pory dobrze to rozplanowałem - sposób w jaki zaplanować klasy CzescRozkazowa i CzescKomentarzowa.
Przyszłościowo przewiduję, że moge potrzebować rozszerzyc program o opcję zmian wartosci argumentów rozkazów ON i OFF (WAITON oraz WAITOFF i innych) z wartości jaką maja na nową w całym programie (oraz we wszystkich programach na maszynie).
Za wszelkie podpowiedzi będę wdzięczny.