Kilka pytań o poprawność, techniki

0

Witam, tym razem kilka pytań bardziej opisowych.

  1. Dajemy na to, że mam zaimplementować wzorzec iteratora, który będzie sortował obiekty klasy według różnych kryteriów. Mam interfejs, który ma metody First, Next, CurrentItem, IsDone.

Teraz rozumiem, że ten interefejs muszą implementować oddzielne klasy dla każdego sortowania. Np. IteratorDateAsc, IteratorDateDsc, itp.

Problem w tym, że ten kod zajmuje trochę miejsca, a różni się szczegółami. Natomiast taka metoda jak CurrentItem czy IsDone jest w ogóle powtarzana. Mimo tego, że programuje od niedawna, to wydaje mi się, że jest to złe podejście. W jaki sposób NAJLEPIEJ do tego podejść? Wszystko mi działa, ale przy 7 kryteriach sortowania mam masę kodu.

  1. Teraz zupełnie inny przykład. Mam jeden button, który uruchamia dwie różne metody i każda z metod pisze coś do innego TextBoxa, to co jest tam pisane, jest uzależnione od RadioButtona.

Przycisk "Pisz" ma się aktywować, gdy w obu GroupBoxach zostanie cokolwiek zaznaczone. Rozwiązałem to, ale wydaje mi się, że znowu niezbyt optymalnie / poprawnie.

private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (!flagGroup1 || !flagGroup2)
            {
                var s = sender as RadioButton;

                if (s.Checked)
                {
                    //Tworzę dwie grupy kontrolek RadioButton:
                    var groupRadioButtons1 = groupBox1.Controls.OfType<RadioButton>();
                    var groupRadioButtons2 = groupBox2.Controls.OfType<RadioButton>();

                    foreach (var item in groupRadioButtons1)
                    {
                        if (item == s)
                        {
                            flagGroup1 = true;
                            break;
                        }
                    }

                    foreach (var item in groupRadioButtons2)
                    {
                        if (item == s)
                        {
                            flagGroup2 = true;
                            break;
                        }
                    }

                    if (flagGroup1 && flagGroup2)
                        btnUruchom.Enabled = true;
                }
            }
        }

Jakieś rady? Przykład służy jedynie poznaniu trochę języka, więc nie chciałbym się uczyć jakiś złych metod.

  1. Mam dwa textBoxy, do których jest coś pisane w dwóch oddzielnych wątkach. Żeby nie tworzyć dwóch metod, zrobiłem jedną jednak nie wiem jak ją sparametryzować, żeby pisała do odpowiedniej kontrolki. Przykład, który znowu działa, ale wydaje mi się średni:
private void AppendTextToTextBoxes(string text, string methodName)
        {
            if (InvokeRequired)
            {
                AppendTextDelegate myDelegate = new AppendTextDelegate(AppendTextToTextBoxes);
                Invoke(myDelegate, new object[] { text, methodName });
            }
            else
            {
                if (methodName == "first")
                    txtFirst.Text += text;
                else //w drugiej przekazuje parametrem inną nazwę
                    txtSecond.Text += text;
            }
        }

Wywoływanie odbywa się:

AppendTextToTextBoxes(text, "first");

Znowu to samo pytanie, czy robię to poprawnie, czy zbyt chałupniczo?

  1. Pytanie takie ogólne... jak się uczyć "ładnego" pisania? Bo wiadomo, że to, że coś działa, niekoniecznie jest dobrze napisane. Nie chciałbym pisać tak, żeby wstyd było kod pokazywać, a nie bardzo mam z kim to konsultować. Skończyłem drugi rok studiów i u mnie raczej żaden z kolegów nie dba o jakość kodu, bo prowadzący też raczej tego nie wymuszają.

  2. Czy żeby mieć dostęp do kontrolek z jednej formy w drugiej, to dobrym pomysłem jest robienie tego przez konstruktor?

  3. EntityFramework: jeśli mam zrobioną bazę danych i odwołuję się wielokrotnie do modelu, tworząc jego nowe instancje, to powinienem używać Singletonu? Czy nie jest to przerost formy nad treścią? Czy jeśli zaktualizuję bazę, to używając starej instancji modelu będą miał aktualne dane?

  4. Możecie polecić jakieś DOBRE materiały, do nauczenie się tworzenia bazy danych podejściem "Code First" w LINQ TO SQL? Piszę troszeczkę też pod WindowsPhone i tam chyba nie ma innej opcji dostępu do lokalnej bazy danych, niż to... a przyznam, że nie bardzo lubię w ten sposób tworzyć bazę, nie czuję tej metody. Zdecydowanie wolę tworzyć graficznie model, ewentualnie napisać to w zwykłym SQL i jedynie korzystając z ORM mapować to na klasy.

  5. Czy Wy znacie na pamięć wszystko, co implementuje IDisposable? Jest jakiś dodatek, który podkreślałby mi takie obiekty, żebym nie zapominał zwalniać po nich pamięci? Ewentualnie jakieś narzędzia, które mi "pokażą", że pamięć się nie zwalania? Najlepiej coś prostego, czego mógłbym używać bez wcześniejszego miesięcznego czytania.

Dodam, że to są takie rzeczy, na które natrafiłem podczas samodzielnej nauki, nie jest to żadne zaliczenie i dlatego nie wystarcza mi, że "działa". Nikt kodu oglądał nie będzie i chciałbym po prostu wiedzieć, że robię to poprawnie.

Pozdrawiam

1
TruEE napisał(a):

Problem w tym, że ten kod zajmuje trochę miejsca, a różni się szczegółami. Natomiast taka metoda jak CurrentItem czy IsDone jest w ogóle powtarzana. Mimo tego, że programuje od niedawna, to wydaje mi się, że jest to złe podejście. W jaki sposób NAJLEPIEJ do tego podejść? Wszystko mi działa, ale przy 7 kryteriach sortowania mam masę kodu.

Trochę nie wiem, po co używać iteratora do sortowania, ale identyczne metody możesz przecież umieścić w jakiejś klasie bazowej.

Przycisk "Pisz" ma się aktywować, gdy w obu GroupBoxach zostanie cokolwiek zaznaczone. Rozwiązałem to, ale wydaje mi się, że znowu niezbyt optymalnie / poprawnie.

Może coś takiego?

private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (!flagGroup1 || !flagGroup2)
            {
                var s = sender as RadioButton;

                if (s.Checked)
                {
                     btnUruchom.Enabled = groupBox1.Controls.OfType<RadioButton>().Any(x => x == s) &&  groupBox2.Controls.OfType<RadioButton>().Any(x => x == s);
                }
            }
        }
  1. Mam dwa textBoxy, do których jest coś pisane w dwóch oddzielnych wątkach. Żeby nie tworzyć dwóch metod, zrobiłem jedną jednak nie wiem jak ją sparametryzować, żeby pisała do odpowiedniej kontrolki.

A nie możesz po prostu przekazać w parametrze metody tej kontrolki?

  1. Pytanie takie ogólne... jak się uczyć "ładnego" pisania? Bo wiadomo, że to, że coś działa, niekoniecznie jest dobrze napisane. Nie chciałbym pisać tak, żeby wstyd było kod pokazywać, a nie bardzo mam z kim to konsultować. Skończyłem drugi rok studiów i u mnie raczej żaden z kolegów nie dba o jakość kodu, bo prowadzący też raczej tego nie wymuszają.

Przy pisaniu nie stosuj kopiuj-wklej, i pisz, aż dojdziesz do wniosku, że nie możesz już nic nie poprawić. I przeczytaj "Czysty kod", książka bardzo radykalna, ale daje do myślenia.

  1. Czy żeby mieć dostęp do kontrolek z jednej formy w drugiej, to dobrym pomysłem jest robienie tego przez konstruktor?

Nie.
Jeśli chodzi o proste i chałupnicze rozwiązania, to niech forma udostępnia publiczne metody, które operują na jej kontrolkach, a do drugiej formy w konstruktorze przekazuj tylko tę formę.
Ale lepszym rozwiązaniem jest zastosowanie np. wzorca MVP.

  1. EntityFramework: jeśli mam zrobioną bazę danych i odwołuję się wielokrotnie do modelu, tworząc jego nowe instancje, to powinienem używać Singletonu? Czy nie jest to przerost formy nad treścią? Czy jeśli zaktualizuję bazę, to używając starej instancji modelu będą miał aktualne dane?

Nie powinieneś absolutnie używać singletona ani starych instancji. Tworzysz nowy obiekt modelu na potrzeby konkretnej operacji, którą chcesz wykonać, a po zakończeniu go zwalniasz (metodą Dispose).

  1. Możecie polecić jakieś DOBRE materiały, do nauczenie się tworzenia bazy danych podejściem "Code First" w LINQ TO SQL?

A jesteś pewien, że tak się w ogóle da?

  1. Czy Wy znacie na pamięć wszystko, co implementuje IDisposable? Jest jakiś dodatek, który podkreślałby mi takie obiekty, żebym nie zapominał zwalniać po nich pamięci? Ewentualnie jakieś narzędzia, które mi "pokażą", że pamięć się nie zwalania? Najlepiej coś prostego, czego mógłbym używać bez wcześniejszego miesięcznego czytania.

Resharper (taki dodatek do Visual Studio) sugeruje takie rzeczy.

Nikt kodu oglądał nie będzie i chciałbym po prostu wiedzieć, że robię to poprawnie.

No raczej się nie dowiesz bez pokazywania komuś kodu.

1

Mam interfejs, który ma metody First, Next, CurrentItem, IsDone.

Po co wymyślać nowy, skoro jest IEnumerable zawierające Reset, Current i MoveNext? Do tego ładnie się integruje z resztą języka: foreach i LINQ.

Czy Wy znacie na pamięć wszystko, co implementuje IDisposable?

Nie. Ale:
• często używane klasy się pamięta
• reszta na czuja: jeśli podejrzewamy że może być IDisposable, to sprawdzamy. najszybciej jest sprawdzić, czy środowisko podpowiada metodę Dispose.

w ostateczności, tragedia się nie dzieje gdy zabraknie using/Dispose. zazwyczaj oznacza to większą zajętość pamięci przez program, ale gdy będzie potrzeba, GC nad tym zapanuje.

Czy żeby mieć dostęp do kontrolek z jednej formy w drugiej, to dobrym pomysłem jest robienie tego przez konstruktor?
Dobrym pomysłem jest nie mieć dostępu do kontrolek z jednej formy w drugiej, a komunikację między formami zrobić na eventach.

0
somekind napisał(a):

Trochę nie wiem, po co używać iteratora do sortowania, ale identyczne metody możesz przecież umieścić w jakiejś klasie bazowej.

Przyznaję, że przykład dość mocno naciągany. Kiedyś na studiach jako przykład tego wzorca miałem podane przechodzenie po kolekcji jakiejś własnej klasy, bez tworzenia jej kopii i najlepiej w wątkach, żeby pokazać, że iterator idzie sobie po niej niezależnie i w tym samym czasie mogę wypisywać nazwiskami rosnąco, oraz malejąco. Dla przećwiczenia to zaimplementowałem, nie jest to fragment żadnej większej aplikacji. To nie jest istotne, ale mam pytanie odnośnie dalszej częsci Twojej odpowiedzi. Oczywiście mogę to umieścić w klasie bazowej, ale wtedy muszę w niej implementować wszystkie metody, a nie wszystkie chce (dokładnie nie chce implementować np. metody Next()).

Teraz znowu nie wiem, czy to ma sens.

public interface ITest
        {
            void Test1(); // chce zaimplementować 
            void Test2(); //nie chcę
            void Test3(); //nie chcę 
        }

        public class BaseClass : ITest
        {
            public void Test1()
            {
                //tutaj kod, który będzie wszędzie
            }

            //te dwie zostawiam puste, żeby się skompilowało
            public virtual void Test2() { }
            public virtual void Test3() { }
        }

        public class Something : BaseClass, ITest
        {
            public override void Test2()
            {
                //kod klasy konkretnej
            }

            public override void Test3()
            {
                //kod klasy konkretnej
            }
        }

Rzecz w tym, że teraz środowisko nie wymusi implementacji Test2 i Test3. Jeśli piszę coś samemu, to okej, ale jeśli kod dam np. koledze, to może to pominąć. Chyba, że poprawnym rozwiązaniem będzie rozbicie tego głównego Interfejsu na dwa inne.

somekind napisał(a):

Może coś takiego?

Super!

somekind napisał(a):

A nie możesz po prostu przekazać w parametrze metody tej kontrolki?

Jasne, że mogę, nie wiem czemu nie pomyślałem o tym.

Azarien napisał(a):

Po co wymyślać nowy, skoro jest IEnumerable zawierające Reset, Current i MoveNext? Do tego ładnie się integruje z resztą języka: foreach i LINQ.

To było tylko tak dla testu, te metody mogłby być inne. Wiem, że w powinienem użyć IEnumerator.

Azarien napisał(a):

Dobrym pomysłem jest nie mieć dostępu do kontrolek z jednej formy w drugiej, a komunikację między formami zrobić na eventach.

Byłbym wdzięczny za podrzucenie jakiegoś prostego przykładu, chętnie bym zobaczył jak to wygląda! :)

0

Oczywiście mogę to umieścić w klasie bazowej, ale wtedy muszę w niej implementować wszystkie metody, a nie wszystkie chce (dokładnie nie chce implementować np. metody Next()).

Nie musisz. Wystarczy, że swoją klasę bazową oznaczysz jako abstrakcyjną i metody z interfejsu, których nie chcesz implementować oznaczysz jako abstract.

interface IHumanSorter
{
    void Next();
    void Blah();
}

abstract class HumanSorterBase : IHumanSorter
{
    public abstract void Next();

    public virtual void Blah()
    {

    }
}

A na samo sortowanie według wielu kryteriów są inne, bardziej zręczne metody niż tworzenie miliona klas na sztywno. Chociażby podanie jednolinijkowej lambdy do IEnumerable.OrderBy(). Krótkie i silnie typowane.

0
TruEE napisał(a):

Oczywiście mogę to umieścić w klasie bazowej, ale wtedy muszę w niej implementować wszystkie metody, a nie wszystkie chce (dokładnie nie chce implementować np. metody Next()).

Nie musisz. Klasa bazowa ma nie implementować tego interfejsu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1