2010-03-22 10 views
79

Czy istnieją jakieś znane zasady projektowania, najlepsze praktyki i wzorce projektowe, które można zastosować podczas projektowania projektu C? Lub użyteczne zasady projektowania dla programowania proceduralnego (imperatywnego) w ogóle?Zasady projektowania, najlepsze praktyki i wzorce projektowe dla C (lub ogólnie programowania proceduralnego)?

(Jestem dzieckiem „pokolenia” obiektowego i mają zaprojektować duży projekt C po raz pierwszy)

+1

Możesz być zainteresowany anwsers na to pytanie: http://stackoverflow.com/questions/661307/recommendations-for-structuring-complex-applications-in-c – mouviciel

+0

Rzeczywiście, bardzo dziękuję, mouviciel. – Dimi

+7

Zrobiłem kilka badań biblioteki internetowej i uniwersyteckiej, zanim opublikowałem moje pytanie, i zdecydowanie nie byłem przytłoczony książkami o projektowaniu oprogramowania dla C. Pytam cię o twoje ulubione (nie mówię o ogólnych książkach C, nie mówię o konwencjach kodowania jak znaczące nazwy zmiennych, ale o wyższej abstrakcji, poziomie architektury oprogramowania). Co więcej, nie zgadzam się na twoje "poleganie na wyrzutach innych ludzi". Masz na myśli, że każdy programista powinien sam się przekonać o najlepszych praktykach i dobrych wzorcach projektowych? Jest to z pewnością pytanie, na którym należy wykorzystać doświadczenie innych. – Dimi

Odpowiedz

56

ukrywania informacji - jak forsowane przez Parnas (Software Fundamentals).

Staranne zarządzanie nagłówków i widoczności:

  • Wszystko w pliku źródłowym, które mogą być ukryte przed światem zewnętrznym powinno być; udokumentowany powinien być tylko udokumentowany zewnętrzny interfejs.
  • Wszystko, co jest odsłonięte, jest zadeklarowane w nagłówku.
  • Ten nagłówek jest używany tam, gdzie wymagana jest funkcjonalność (i gdzie jest zdefiniowana).
  • Nagłówek jest samowystarczalny - gdy go potrzebujesz, to go używasz i nie musisz martwić się o to, "co inne nagłówki też muszę uwzględnić", ponieważ nagłówek zapewnia jego działanie, włączając w to wszystko, czego potrzebuje aby to działało.
  • Nagłówek jest samoobronny - więc nie ma znaczenia, czy jest on dołączony wiele razy.

    #ifndef HEADER_H_INCLUDED 
    #define HEADER_H_INCLUDED 
    ...rest of header contents, including other #include lines if necessary 
    #endif /* HEADER_H_INCLUDED */ 
    
  • zestawy konstrukcyjne funkcji do pracy na „obiektów” (zwykle struktury) - i korzystać z tych funkcji, zamiast grzebać wnętrzności struktury w kodzie, który wykorzystuje je. Pomyśl o tym jako o samozapaleniu się hermetyzacji.

+0

Dobra uwaga, dziękuję, Jonathan. Abstrakcyjne typy danych są kolejnym dobrym przykładem ukrywania informacji z czystym rozdziałem użycia i implementacji (znany interfejs zewnętrzny i nieznana implementacja wewnętrzna). – Dimi

20

Jest to dobry, bezpłatny, internetowy książka zatytułowana Object-Oriented Programming With ANSI-C, która obejmuje tematykę pisania kodu obiektowego w C. google search dla „obiektowym C” daje również szereg innych dobrych przykładów i zasoby.

Jeśli twój projekt jest krytyczny dla bezpieczeństwa, MISRA-C to dobry zestaw reguł. Jest przeznaczony głównie dla osadzonych c, ale może być przydatny także w innych obszarach.

Uważam się za kodera OO i wykonuję wiele pracy z osadzonym C. Najlepszą radą, jaką mogę dać, szczególnie w przypadku dużych projektów, nie jest przesadzanie. Stworzenie kompletnego szkieletu OO na szczycie ANSI C może być bardzo kuszące, ale potrzeba sporo czasu i wysiłku, by to naprawić. Im jesteś hodowcą, tym więcej czasu poświęcisz na debugowanie szkieletu zamiast pracy nad projektem rzeczywistym. Podejdź do zadania z wyraźną głową i dobrym, solidnym chwytem YAGNI. Powodzenia!

+0

Dziękuję, e.James. Nie chcę tworzyć obiektowych ram na szczycie ANSI C, ale szukam specjalnych i odpowiednich zasad projektowania programowania proceduralnego. Wskazówka MISRA-C jest bardzo przydatna, szczególnie dlatego, że w rzeczywistości jest to projekt osadzony. Przyjrzę się temu bliżej. – Dimi

+0

Ach, radości osadzonego C. Nie zapominaj, że musisz zadeklarować swoje zmienne u góry swojej funkcji (lub u góry dowolnego bloku '{}'). Ten zawsze mnie ugryza raz lub dwa razy::) –

6

OOP to metodologia, a nie technologia. Pierwszą moją radą jest przestać myśleć o tym jako o proceduralnym programowaniu.

Do punktu e.James nie należy próbować odtwarzać języka zorientowanego obiektowo lub udawać, że posiada on odpowiednie możliwości. Nadal możesz robić wszystkie właściwe rzeczy, trzymając się kilku prostych zasad:

  1. Przetestuj wszystko.
  2. Znajdź to, co jest różne i obuduj je.
  3. Zaprojektuj interfejsy.
19

Moje trzy porady:

  • testów jednostkowych pisać. Pomogą ci zerwać z projektem, który będzie pasował do twojego problemu, kiedy będziesz postępować. O wiele lepsze niż poleganie (wyłącznie) na myśleniu przed medytacją.
  • Mieć wykrywacz wycieków pamięci (są różne rodzaje bibliotek) zainstalowane i uruchomione od pierwszego dnia. Niech ta biblioteka wydrukuje wszystkie wycieki po zakończeniu programu/testów. Pozwoli ci to złapać przeciek zaraz po wprowadzeniu go, przez co jego utrwalanie stanie się mniej bolesne.
  • Napisz kod OOP w C. Nie jest to trudne. Chociaż możliwe jest emulowanie nadpisywania metod, sugeruję rozpoczęcie od emulacji prostych obiektów. Nawet ten prosty mechanizm może zapewnić duży przebieg.

Oto przykład:

struct Vector { 
    int size; 
    int limit; 
    int* ints; 
} 

Vector* Vector_new() { 
    Vector* res = (Vector*) malloc(sizeof(Vector)); 
    res->limit = 10; 
    res->size = 0; 
    res->ints = (int*) malloc(sizeof(int) * res.limit); 

    return res; 
} 


void Vector_destroy(Vector* v) { 
    free(v->ints); 
    free(v); 
} 

void Vector_add(Vector* v, int n) { 
    if(v->size == v->limit) { 
    v->limit = v->limit * 2 + 10; 
    v->ints = realloc(v->ints, v->limit);  
    } 

    v->ints[v->size] = n; 
    ++v->size; 
} 

int Vector_get(Vector* v, int index) { 
    if(index >= 0 && index < v->size) 
    return v->ints[index]; 

    assert false; 
} 
+0

Dziękuję, Itay. Pójdę za twoimi radami. – Dimi

+0

Świetny prosty przykład. ('< v-> size()' w 'Vector_get' powinno być bez'() 'Chyba?) – Carl

+0

@Carl - Dzięki, Naprawiono. –

Powiązane problemy