PR02
PR02
Nečist kôd
Kôd koji narušava (dobar) objektno orijentiran dizajn
◦ Osnovna klasa
◦ Izvedene klase
◦ Apstraktne klase
◦ Sučelja
Nasljeðivanje
Omogućuje izgradnju hijerarhije klasa putem veza tipa JE (engl. "is a")
1 class BaseClass
2 {
3 private int _ID = 0;
4 protected string FirstName = "Base";
5 protected string LastName = " Class ";
6
7 public string GetName () {
8 return this. FirstName + this. LastName ;
9 }
10 public int ID { get { return this._ID; } }
11 }
12
13 class DerivedClass : BaseClass
14 {
15 public DerivedClass () {
16 this. FirstName = " Derived ";
17 }
18 // skriva metodu osnovne klase
19 public new string GetName () { // kljucna rijec new nije obavezna
20 return this. FirstName + " " + this. LastName ;
21 }
22 }
1 class Program
2 {
3 static void Main ()
4 {
5 BaseClass Super = new BaseClass ();
6 DerivedClass Sub = new DerivedClass ();
7
8 Console . WriteLine ("Base class name: " + Super . GetName ()
9 + " and ID: " + Super .ID );
10 Console . WriteLine (" Derived class name: " + Sub. GetName ()
11 + " and ID: " + Sub.ID );
12 }
13 }
1 class Program {
2 static void Main () {
3 DerivedClass Sub = new DerivedClass ();
4 Console . WriteLine (Sub. GetSummary ());
5 }
6 }
Polimorfizam
Mogućnost da neki objekt poprimi više različitih oblika
1 class Program
2 {
3 static void Main ()
4 {
5 DerivedClass Sub = new DerivedClass ();
6 BaseClass Super = Sub;
7
8 Console . WriteLine ( Super );
9 Console . WriteLine (Sub );
10 }
11 }
1 class Program
2 {
3 static void Main ()
4 {
5 Base [] baseForms = new Base [] {
6 new DerivedOne (),
7 new DerivedTwo (),
8 new DerivedThree ()};
9
10 foreach (Base form in baseForms ) {
11 string name = form. GetName ();
12 Console . WriteLine (name );
13 }
14 }
15 }
1 interface INameProvider
2 {
3 string GetFirstName ();
4 string GetLastName ();
5 }
6
7 class Person : INameProvider
8 {
9 private string FirstName ;
10 private string LastName ;
11 public Person ( string name) {
12 string [] names = name. Split (’ ’);
13 this. FirstName = names [0];
14 this. LastName = names [1];
15 }
16 public string GetFirstName () {
17 return this. FirstName ;
18 }
19 public string GetLastName () {
20 return this. LastName ;
21 }
22 }
1 class Program
2 {
3 static void Main ()
4 {
5 Person person = new Person ("Otto Hermann ");
6
7 PrintName ( person );
8 }
9
10 static void PrintName ( INameProvider name)
11 {
12 string firstName = name. GetFirstName ();
13 string lastName = name. GetLastName ();
14 Console . WriteLine ( firstName + " " + lastName );
15 }
16 }
S.O.L.I.D. načela
Pet važnih načela objektno orijentiranog razvoja čija je svrha učiniti
tekst programa jednostavnijim za održavanje i proširivanje
1 class Contact {
2 private int _ID;
3 public string FirstName { get; private set; }
4 public string LastName { get; private set; }
5 ...
6 }
7
8 class PhoneBook {
9 private List <Contact > contacts ;
10
11 // odgovornost
12 public void Insert ( Contact c, string logMessage ) {
13 ...
14 LogInsertion ( logMessage );
15 }
16
17 // jos jedna odgovornost , ali ne bi trebala biti od klase PhoneBook
18 public void LogInsertion ( string message ) { ... }
19 }
1 class Contact {
2 ...
3 }
4
5 class PhoneBook {
6 private List <Contact > contacts ;
7
8 public void Insert ( Contact c) {
9 ...
10 }
11 }
12
13 // neprikladna odgovornost izdvojena u posebnu klasu
14 class LogService
15 {
16 public void Log( Contact contact , string message ) { ... }
17 }
1 class Contact {
2 ...
3 }
4
5 class PhoneBook {
6 private List <Contact > contacts ;
7
8 public void Insert ( Contact c) {
9 ...
10 }
11
12 // treba li biti odgovornost klase PhoneBook ?
13 public void ExportToXML () { ... }
14 }
1 class Contact {
2 ...
3 }
4
5 class PhoneBook {
6 private List <Contact > contacts ;
7
8 public void Insert ( Contact c) {
9 ...
10 }
11 }
12
13 // neprikladna odgovornost izdvojena u posebnu klasu
14 class ContactsExporter {
15 ...
16 public void ExportToXML ( PhoneBook contacts ) { ... }
17 }
1 interface ILogable
2 {
3 string GetMessageHeader ();
4 }
5
6 abstract class Contact
7 {
8 ...
9 }
10
11 class HomeContact : Contact , ILogable
12 { // eksplicitna ugradnja sucelja
13 string ILogable . GetMessageHeader () { return "HOME: "; }
14 }
15 class MobileContact : Contact , ILogable
16 { // eksplicitna ugradnja sucelja
17 string ILogable . GetMessageHeader () { return " MOBILE : "; }
18 }
1 class LogService
2 {
3 public void Log( ILogable obj , string message ) {
4 string header = obj. GetMessageHeader ();
5 Console . WriteLine ( header + message );
6 }
7 }
1 class TextFile
2 {
3 public virtual string Read () { ... }
4 public virtual void Write ( string text) { ... }
5 }
6
7 class ReadOnlyTextFile : TextFile
8 {
9 public override string Read () { ... }
10 public override void Write ( string text) {
11 throw new NotImplementedException ();
12 }
13 }
1 class TextFileManager
2 {
3 // klijent zna samo za klasu TextFile
4 List <TextFile > files ;
5 public Files { set { files = value ; } }
6
7 public string LinkTextFiles () {
8 StringBuilder linkedFiles = new StringBuilder ();
9 foreach ( TextFile file in files ) {
10 linkedFiles . Append (file.Read ());
11 }
12 return linkedFiles ;
13 }
14
15 // klijent zna da klasa TextFile pruza citanje i pisanje
16 public void ModifyTextFiles ( string text) {
17 foreach ( TextFile file in files ) {
18 file. Write (text );
19 }
20 }
21 }
1 class TextFileManager
2 {
3 // klijent zna samo za klasu TextFile
4 List <TextFile > files ;
5 public Files { set { files = value ; } }
6
7 public string LinkTextFiles () {
8 StringBuilder linkedFiles = new StringBuilder ();
9 foreach ( TextFile file in files ) {
10 linkedFiles . Append (file.Read ());
11 }
12 return linkedFiles ;
13 }
14
15 //" rjesenje " koje krsi OCP
16 public void ModifyTextFiles ( string text) {
17 foreach ( TextFile file in files ) {
18 if (file. GetType () != typeof ( ReadOnlyTextFile ))
19 file. Write (text );
20 }
21 }
22 }
1 interface IReadable
2 {
3 string Read ();
4 }
5
6 interface IWritable
7 {
8 void Write ( string text );
9 }
1 class TextFileManager
2 {
3 public string LinkTextFiles (List <IReadable > files ) {
4 StringBuilder linkedFiles = new StringBuilder ();
5 foreach ( IReadable file in files ) {
6 linkedFiles . Append (file.Read ());
7 }
8 return linkedFiles ;
9 }
10
11 public void ModifyTextFiles (List <IWritable > files , string text) {
12 foreach ( IWritable file in files ) {
13 file. Write (text );
14 }
15 }
16 }
1 interface IProcessable
2 {
3 string Read ();
4 void Write ( string text );
5 }
6
7 class TextFile : IProcessable
8 {
9 public string Read () { ... }
10 public void Write ( string text) { ... }
11 }
12
13 class ReadOnlyTextFile : IProcessable
14 {
15 public string Read () { ... }
16 public void Write ( string text) {
17 throw new NotImplementedException ();
18 }
19 }
1 interface IReadable
2 {
3 string Read ();
4 }
5
6 interface IWritable
7 {
8 void Write ( string text );
9 }
10
11 class TextFile : IReadable , IWriteable
12 {
13 public string Read () { ... }
14 public void Write ( string text) { ... }
15 }
16
17 class ReadOnlyTextFile : IReadable
18 {
19 public string Read () { ... }
20 }
1 class Contact {
2 public Name { get; set; }
3 public Address { get; set; }
4 public PhoneNumber { get; set; }
5 public EmailAddress { get; set; }
6 }
1 interface IEmailable {
2 string Name { get; set; }
3 string EmailAddress { get; set; }
4 }
5
6 interface IPhoneable {
7 string PhoneNumber { get; set; }
8 }
9
10 class Contact : IEmailable , IDiallable {
11 public Name { get; set; }
12 public Address { get; set; }
13 public PhoneNumber { get; set; }
14 public EmailAddress { get; set; }
15 }
1 class Email
2 {
3 public void Send( string message )
4 }
5
6 class NotificationService
7 {
8 Email email ;
9 // sto ako bude potreban drugi oblik dostave poruka ?
10 public NotificationService () {
11 email = new Email ();
12 }
13
14 public void Broadcast ( string message ) {
15 ...
16 email .Send( message );
17 }
18 }
1 interface IMessenger
2 {
3 void Send( string message );
4 }
5
6 class Email : IMessenger
7 {
8 public void Send( string message ) { ... }
9 }
10
11 class SMS : IMessenger
12 {
13 public void Send( string message ) { ... }
14 }
1 class NotificationService
2 {
3 IMessenger MessagingService ;
4
5 public NotificationService ( IMessenger service ) {
6 this. MessagingService = service ;
7 }
8
9 public void Broadcast ( string message ) {
10 ...
11 MessagingService .Send( message );
12 }
13 }
1 class NotificationService
2 {
3 IMessenger _MessagingService ;
4
5 public IMessenger MessagingService {
6 set { _MessagingService = value ; }
7 private get { return this. _MessagingService ; }
8 }
9
10 public void Broadcast ( string message ) {
11 ...
12 MessagingService .Send( message );
13 }
14 }
1 class NotificationService
2 {
3 public void Broadcast ( IMessenger service , string message ) {
4 ...
5 service .Send( message );
6 }
7 }
1
Zavidna metoda (engl. feature envy)
(FERIT) DOOP PR 63 / 111
Mirisi u kôdu Nakupine podataka
2
Nakupine podataka (engl. data clumps)
(FERIT) DOOP PR 64 / 111
Mirisi u kôdu Odbijeno nasljedstvo
3
Odbijeno nasljedstvo (engl. refused bequest)
(FERIT) DOOP PR 65 / 111
Mirisi u kôdu Lijene klase
4
Lijena klasa (engl. lazy class)
(FERIT) DOOP PR 66 / 111
Mirisi u kôdu Privremeni atributi
5
Privremeni atribut (engl. temporary field)
(FERIT) DOOP PR 67 / 111
Mirisi u kôdu Divergentne promjene
6
Divergentna promjena (engl. divergent change)
(FERIT) DOOP PR 68 / 111
Mirisi u kôdu Operacije sačmarom
7
Operacije sačmarom (engl. shotgun surgery)
(FERIT) DOOP PR 69 / 111
Mirisi u kôdu Podatkovne klase
8
Podatkovna klasa (engl. data class)
(FERIT) DOOP PR 71 / 111
Mirisi u kôdu Opežna uporaba komentara
10
Čovjek u sredini (engl. middle man)
(FERIT) DOOP PR 76 / 111
Mirisi u kôdu Sažetak
S.T.U.P.I.D. kôd
Šest čestih pristupa pisanju kôda koji ga čine teškim za održavanje,
proširivanje i testiranje
◦ Singleton
◦ Tight coupling
◦ Untesability
◦ Premature opitmisation
◦ Indescriptive naming
◦ Duplication
"Any fool can write code that a computer can understand. Good
programmers write code that humans can understand."
Martin Fowler