14 Nisan 2013 Pazar

GÖZLEMCİ TASARIM MODELİ(OBSERVER DESIGN PATTERN)

Observer pattern,değişiklik yaşanan durum hakkında gerekli birimleri bilgilendirmek için kullanılan bir patern yapısıdır.Observer pattern yapısının genel uml diagramı yandaki gibidir.Peki ne anlatıyor bize bu uml diagram?
Öncelikle elimizde gözlenen(subject) ve gözlemci(observer) sınıfımız olmak zorundadır.Gözlemci sınıfımız altında bulunan update() fonksiyonuyla subject yani gözlenen sınıfında meydana gelen değişikliklerden haberdar edilir.Subject sınıfımızda da addObserver() ve deleteObserver() fonksiyonlarıyla değişen durumlardan haberdar olacak gözemciyi ekleme ve silme işlemleri yapılır.notifyObserver() fonksiyonu ise Observer sınıfının update() fonksiyonunu çağırarak değişikliklerden haberdar etmiş olur.
Observer Pattern yapısı,fonksiyonları bu şekildedir.Fonksiyonların işleyişini örnek bir uygulama üzerinden anlatalım...

Yandaki resimde görüldüğü gibi uygulamamız restaurantta verilen siparişlerin işleyişleri hakkında olacaktır.Mutfakta çalışan aşçımız,kasada bulunan kasiyer ve siparişi alan garson bulunmaktadır.Aşçı yapacağı yemekleri bilmek,kasiyerde yemeklerden alınması gereken parayı bilmek ister.O zaman garson sipariş alınca hem aşçıyı hem de kasiyeri bilgilendirsin.Elimizde bu durum da iki gözlemci; mutfak(Kitchen) ,kasiyer(Chaier) ve bir de gözlenen/öznemiz garson (Waiter) vardır.




Uml aşağıdaki gibi olacaktır...

















İşte kodumuz.....


#include<iostream>
#include<vector>
#include<string>
#include<list>

using namespace std;

//***********
//Observer
//***********
class Observer
{
public:
virtual void updata(string s,int i,double d)=0;
};

/***********
//Chaier
//***********
class Chaier:public Observer,Display
{
Waiter *w;
vector<string> name;
vector<int >number;
vector<double >cost;
public:
Chaier(Waiter *w)
{
this->w=w;
w->registerObserver(this);
}
~Chaier()
{
w->removeObserver(this);
}
void updata(string new_name,int new_number,double new_cost)
{
name.push_back(new_name);
number.push_back(new_number);
cost.push_back(new_cost);
display();
}
void display()
{
double total_cost=0;
cout<<endl<<"***************** CHAIER DISPLAY ***************"<<"\n\n";
cout<<"Name       Number     Cost"<<endl<<"--------------------------"<<"\n";
for(int i=0;i<name.size();i++)
{
cout<<name[i]<<"         "<<number[i]<<"        "<<number[i]*cost[i]<<"\n";
total_cost+=number[i]*cost[i];
}
cout<<endl<<"TOTAL COST : "<<total_cost<<"\n";
}
};

//***********
//Kitchen
//***********
class Kitchen:public Observer,Display
{
Waiter *w;
vector<string> name;
vector<int >number;
vector<double >cost;
public:
Kitchen(Waiter *w)
{
this->w=w;
w->registerObserver(this);
}
~Kitchen()
{
w->removeObserver(this);
}
void display()
{

cout<<endl<<"************ KITCHEN DISPLAY **************"<<"\n\n";
cout<<"Name       Number"<<endl<<"---------------------"<<"\n\n";
for(int i=0;i<name.size();i++)
{
cout<<name[i]<<"        "<<number[i]<<"      "<<"\n";
}
}
void updata(string new_name,int new_number,double new_cost)
{
name.push_back(new_name);
number.push_back(new_number);
cost.push_back(new_cost);
display();
}

};

//***********
//Display
//***********
class Display
{
public:
virtual void display()=0;
};

//***********
//Subject
//***********
class Subject
{
protected:
string name;
int number;
double cost;
list<Observer*> observer; //Tüm izliyicelerin tutulduğu liste
public:
virtual void registerObserver(Observer *o)=0;
virtual void removeObserver(Observer *o)=0;
virtual void notifyObserver()=0;

};

//***********
//Waiter
//***********
class Waiter:public Subject
{
public:
void registerObserver(Observer *o)
{
observer.push_back(o);
}
void removeObserver(Observer *o)
{
observer.remove(o);
}
void notifyObserver() //Tüm izlyicilerin bilgilerini yeniler.
{
for(list<Observer*>::iterator it=observer.begin();it!=observer.end();it++)
(*it)->updata(name,number,cost);
}
void setOrder(string name,int number,double cost)
{
this->name=name;
this->number=number;
this->cost=cost;
         notifyObserver();
}

};

//***********
//Main
//***********
int main()
{
Waiter *waiter=new Waiter();

Kitchen *kitchen=new Kitchen(waiter); //Kitchen gözlemci olarak eklenniyor.
Chaier *chaier=new Chaier(waiter);    // Chaier gözlemci olarak ekleniyor.

waiter->setOrder("Waffle",2,10);
waiter->setOrder("Kumpir",3,7.5);

delete kitchen; //Kitchen gözlemcilerden çıkarılıyor.Artık değişikliklerden haberda edilmeyecek.

waiter->setOrder("Sutlac",1,7.50);
system("pause");
return 0;
}
Buda output...










10 Nisan 2013 Çarşamba

JAVA'DA SOYUT SINIF(ABSTRACT CLASS)

Kalıtım(inheritance) konusundan bildiğimiz üzere bir süper sınıf ve onun alt sınıflarında oluşur.Soyut sınıflar da bu aşamada işe yarıyor.Görevleri birleştiricilik yapmaktır yani alt sınıflar için süper sınıf olurlar.Soyut sınıfları  şimdiye kadar  oluşturduğumuz sınıflardan farklı yapan şey bu sınıfın eksik bir sınıf oluşu diyebiliriz.Ne demek bu? Normalde bir sınıf oluşturduğumuzda tüm fonksiyonların gövdesini(body) yazıyorduk.Ancak soyut sınıflarda en az bir metodunun gövdesi yazılmaz.Bu metotlara soyut metot denir ve bu metotlar alt sınıflar için ortak  kullanılan,işlevi aynı olan fakat döndürdükleri değer açısından farklılık gösteren fonksiyonlardır ve her  alt sınıfta override edilmek zorundadır.
Soyut sınıflarda  yapılandırıcılar(contructor),static metotlar soyut metot olamazlar ve bu sınıflardan nesne üretilemez.
Java'da soyut sınıf gösterimi abstract anahtar sözcüğü ile yabılmaktadır.extends kelimesiylede alt sınıfı super sınıfa bağlarız (inherit etmesini sağlarız).Kullanımı şu şekildedir:

public abstract class super_class_name //sınıf tanımlaması
{
         public abstract data_type method_name(); //soyut method tanımlaması
         //other function with body
}
 public class derived_class_name extends super_class_name //alt sınıf tanımlaması
{
   //override...
   //other functions
}


Şimdi de örnek bir uygulama yazalım.Oldukça basit bit  bir örnek.Şekill adında  super soyut sınıfımız var ve alt sınıfları kare ve dikdörtgendir(İstediğimiz kadar şekil ekleyebiliriz.).Alt sınıfların ortak yaptıkları işlev alan hesaplamadır.Bu nedenle alan metodumuzu soyut metot yapacağız.


//*************
//Şekill
//*************
package AbstractClass;

public abstract class Şekill {
	public abstract double alan(); 

}
//*************
//Kare
//*************
package AbstractClass;

public class Kare extends Şekill{
	private double kenar1;
	public Kare(double kenar1)
	{
		this.setKenar1(kenar1);
	}
	public double getKenar1() {
		return kenar1;
	}
	public void setKenar1(double kenar1) {
		this.kenar1 = kenar1;
	}
	public double alan()
	{
		return Math.pow(kenar1, 2);
	}

}
//*************
//Dikdörtgen
//*************
package AbstractClass;

public class Dikdörtgen extends Şekill{
	private double kenar1,kenar2;
	
	public Dikdörtgen(double kenar1,double kenar2)
	{
		this.kenar1=kenar1;
		this.kenar2=kenar2;
	}

	public double getKenar1() {
		return kenar1;
	}

	public void setKenar1(double kenar1) {
		this.kenar1 = kenar1;
	}

	public double getKenar2() {
		return kenar2;
	}

	public void setKenar2(double kenar2) {
		this.kenar2 = kenar2;
	}
	public double alan()
	{
		return kenar1*kenar2;
	}
}
//*************
//Mainn
//*************
package AbstractClass;

public class Mainn {

	/**
	 * @author Aylin COSKUN
	 */
	public static void main(String[] args) {
		Şekill sekil=new Kare(3);
		System.out.println("Karenin alanı : "+sekil.alan());
		
		Şekill sekil2=new Dikdörtgen(2, 7);
		System.out.println("Dikdörtgenin alanı : "+sekil2.alan());
		
		
		

	}

}

Main de ne yaptık peki? Şekil sınıfımızdan nesne oluşturamayız bu nedenle sekil adında instance yapıp buna Kare nesnesi atadık.Böylece artık sekill instance artık Kare gibi davranacaktır ve alan metodu çağrıldığında Kare'nin alanını hesaplayacaktır.Dikdörtgen için de aynı şeyleri yaptık...

Son olarakta program çıktımız...



8 Nisan 2013 Pazartesi

STRATEJİ TASARIM MODELİ(STRATEGY DESIGN PATTERN)

 

Strateji model(strategy pattern),bir işlemi yapmak için birden fazla yöntem varsa kullanılır.Her bir strateji için diğer bir deyişle her bir algoritma ailesi için  kapsüllenme yapılır.Böylece programa değişebilirlik özelliği verilir.Yani istenilen yöntem rahatlıkla
eklenebilir,silinebilir.Aksi halde programda if-else bloglarından oluşan bir karmaşa hakim olurdu.
Strategy patternin önemli özelliklerinden biri de programın çalışma esnasında(runtime) değiştirilebilir olmasıdır.Ayrıca yandaki umlden de görüldüğü gibi içerikten(context)  bağımsızdır.

Lafı fazla uzatmadan parmakları çalıştırıp koda dökelim demek istediklerimizi...


Yandaki şekilde görüldüğü üzere helikopter,vapur ve bisiklet olmak üzere üç taşıtım var.Üç taşıtta bir yerden bir yere gidince hangi ulaşım yolunu  kullanılır? Sorunun yanıtı bize ulaşım da kullandıkları strateji yi verecektir.Programımızda da bunu kodlayacağız.Ancak istenildiği kadar taşıt,strategy eklenebilir.Bu programın akışını değiştirmez.
Örneğin ben benzin kullanma,korna çalma gibi yeni stratejilerde ekleyebilirdim.


//*************
//Taşıt
//*************


class Taşıt
{
protected:
	KullanılanYol *k;
public:
	void yol()
	{
		k->kullanılanyol();
	}
	void setYol(KullanılanYol *x)
	{
		k=x;
	}
};

//*************
//Bisiklet
//*************
class Bisiklet:public Taşıt
{
public:
	Bisiklet()
	{
		k=new Kara();
	}

};

//*************
//Helikopter
//*************
class Helikopter:public Taşıt
{
public:
	Helikopter()
	{
		k=new Hava();
	}
};

//*************
//Vapur
//*************

class Vapur:public Taşıt
{
public:
	Vapur()
	{
		k=new Deniz();
	}

};
//*************
//Kullanılan Yol
//*************
#include

using namespace std;

class KullanılanYol
{
public:
	virtual void kullanılanyol()=0;
};

//*************
//Kara Yolu
//*************

class Kara:public KullanılanYol
{
public:
	void kullanılanyol()
	{
		cout<<"Kara yolunu kullanilir...\n";
	}
};

//*************
//Hava Yolu
//*************

class Hava:public KullanılanYol
{
public:
	void kullanılanyol()
	{
		cout<<"Hava yolunu kullanilir...\n";
	}
};

//*************
//Deniz Yolu
//*************
class Deniz:public KullanılanYol
{
public:
	void kullanılanyol()
	{
		cout<<"Deniz yolunu kullanilir...\n";
	}
};
//*************
//Main
//*************
int main()
{
	Taşıt *taşıt=new Bisiklet();
	taşıt->yol();
	taşıt->setYol(new Deniz);
	taşıt->yol();
	cout<<"----------------------------\n";
	Taşıt *taşıt2=new Helikopter();
	taşıt2->setYol(new Kara);
	taşıt2->yol();
	taşıt2->setYol(new Deniz);
	taşıt2->yol();
	



	system("pause");
	return 0;
}

Yukarıdaki kodda maninde önce bisiklet taşıtını çağırdık.Onun yapılandırıcısında yol default olarak kara seçilmiştir.İlk yol fonksiyonu çağrıldığında kara yolu der.Ancak set fonksiyonu ile ben bisikletin kullandığı yolu değiştirdim.İkinci taşıt içinde aynı şeyleri yaptım...

Program çıktımız...



3 Nisan 2013 Çarşamba

JAVA'DA KALITIM(INHERITANCE)

Kalıtım konusuna C++ başlığı altındaki kalıtım(inheritance) adlı yazımda değinmiştim.Zaten mantık hepsi için aynıdır farklı olan ise kullanılan bazı anahtar sözcükler ve metodlardır.Bu yazımda da bunlardan bahsedeceğim.
Kısaca kalıtım neydi?Bir ana/süper sınıf ve ondan türeyen alt sınıfımız vardır.Böylece kod tekrarından kurtularak güvenilir ve kullanışlı programlar yazmış oluruz.
Şimdi de java da  kalıtım(inheritance)  konusuna dönelim.

Extends :Alt sınıfın süper sınıftan miras almasını sağlar.Kullanımı şu şekildedir.
public class derived_class extends super_class{//body}

Super() metodu:Kalıtımda yapılandırıcılar yukarıdan aşağıya yani süper sınıftan alt sınıfa doğru çalışır.Super sınıfın yapılandırıcılarını alt sınıflarda super() metodu ile çağırırız.Eğer super sınıf parametre almışsa super() metodu da onun parametrelerini alır.Aşağıdaki programda belirtilmiştir.

@Override:Metot overriding ile süper sınıfta tanımlanmış aynı isim,parametre ve dönüş tipine  sahip metotların alt sınıflarda kullanımı sağlamak için  kullanılan bir yöntemdir.Metodun işlevi aynıdır fakat değerlerinde ,dönüş tiplerinde değişiklik yapılır.

İşte program....


//*************
//Super class
//**************
package kalitim;
public class personel {
 private String ad;
 private int tc;
 public personel(String ad,int tc)
 {
  this.setAd(ad);
  this.setTc(tc);
 }
 public String getAd() {
  return ad;
 }
       public void setAd(String ad) {
  this.ad = ad;
 }
      public int getTc() {
  return tc;
 }
      public void setTc(int tc) {
  this.tc = tc;
 }
     public String print()
 {
  return "ad : "+getAd()+"\ntc : "+getTc();
 }
}


//*************
//Derived class
//**************
package kalitim;
public class ogrenci extends personel {
 private int okul_no;
 
 public ogrenci(String ad,int tc,int okul_no)
 {
   super(ad,tc);  //super sınıfın parametreli yapılandırıcısı çağrılır ve atama yapılır.
   this.okul_no=okul_no;
 }
 public int getOkul_no() {
  return okul_no;
 }
 public void setOkul_no(int okul_no) {
  this.okul_no = okul_no;
 }
 @Override
 public String print() //print metodu override edilmiştir çünkü okul no eklenmiştir.
 {
  return super.print()+"\nokul no : "+getOkul_no();
 }
}


//*************
//Main
//**************
package kalitim;

public class mainn {

 /**
  * @author Aylin COSKUN
  */
 public static void main(String[] args) {
  personel i=new personel("Aylin COSKUN",12345);
  System.out.println(i.print());
  System.out.println("**********************");
  ogrenci o=new ogrenci("Aynur GUNDOGAN",23456,21);
  System.out.println(o.print());
 }
}


Program çıktısı:








26 Mart 2013 Salı

YAPILANDIRICILAR(CONTRUCTORS)

Bir sınıfın değişkenleri ve fonksiyonları o sınıftan nesne üretilmedikçe hiç bir anlam ifade etmezler.Zaten sınıflar bellekte yer kaplamazlar ama ne zaman ki nesne oluşturulur nesneler hemen bellekte yer edinirler.Peki nesnemizi oluşturduk sizce o sınıftan çağrılan ilk fonksiyon hangisidir?Cevabı tabi ki de yapılandırıcılardır.Yapılandırıcılar nesne oluşturulduğu an çağrılan fonksiyondur.Yani sınıfımızın olmazsa olmaz  metodudur.Belki de şimdiye kadar yazılan basit programlarınızda constructorı siz yazmadınız ama programınız hala hatasız bir şekilde çalışıyor.Bunun cevabı da şu, siz her ne kadar yapılandırıcıyı yazmasanızda , unutsanızda java derleyicisi sizin için siz farkında olmadan bir default contructor yaratır.Ama baktı ki siz yazmışsınız hiç yazma zahmetinde bulunmaz.
Yapılandırıcılarınız public olmalıdır.Eğer başka sınıflarda nesne oluşumunu engellemek istiyorsanız private yapabilirsiniz ama bu özel durumlar haricinde kullanılan bir yol değildir.
Peki yapılandırıcımız hangi özelliklere sahip olmalıdır?

  1. Sınıfla aynı adı taşımak zorundadır.
  2. Dönüş değeri yoktur.
  3. Parametreli ya da parametresiz yapılandırıcı olabilir.
Bu üç özellik bizim temel özelliklerimiz.Artık kodlama zamanııı....


package Constructor;

public class Student {
 private String name;
 private int age;
 private int no;
 //Default contructor
 public Student()
 {
  //Değişkenlerimizin default değerleridir.
  name="There  are no name";
  age=0;
  no=0;
 }
 //Non-default contructor
 public Student(String name,int age,int no)
 {
  this.name=name;
  this.age=age;
  this.no=no;
 }
 public void setname(String name)
 {
  this.name=name;
 }
 public void setage(int age)
 {
  this.age=age;
 }
 public void setno(int no)
 {

  this.no=no;
 }
 public  String printID()
 {
  return "name : "+name+"\n"+"age : "+age+"\n"+"no : "+no.
 }
}


Yukarıdaki sınıfımızın işlevi bir öğrencinin adı yaşı ve numarasını edinmektir.Default contructor,parametreli contructor ,set ve printID() fonksiyonlarım bulunmaktadır.

DEFAULT CONSTRUCTOR:
Parametre almayan contructorlardır.Fonksiyonun body kısmında sınıfın değer atamalarına isteğiniz değerleri atayabilirsiniz.(Ben en başta hiç bir ögrenci olmadığını varsayarak default olarak yukarıdaki değerleri atadım.)

NON-DEFAULT CONTRUCTORS:
Parametre alan yapılandırıcılardır.Kullanıcı nesne oluşturma anında bu değerleri de girer ve sınıfımız değişkenlerine o değerler atanır.

Programımızın main kısmı...


package Constructor;

public class Test_main {

 public static void main(String[] args) {
  
  //Default constructor çağrılır
  Student student=new Student();
  System.out.println(student.printID());
  System.out.println("**********************");
  //Set fonksiyonlar ile default değerlere yeni değerler atanır
  student.setname("Aylin");
  student.setage(21);
  student.setno(1236);
  System.out.println(student.printID());
  System.out.println("**********************");
  //Parametreli yani default olmayan contructor çağrılır
  Student student2=new Student("Anil",22,1163);
  System.out.println(student2.printID());
  }

}




Mainde önce default yapılandırıyı çağırmış olduk çünkü parametre girmedik ve böylece Student sınıfımızın değişkenlerine default yapılandırıcı oluştururken atadığımız değerler atanır.Daha sonra set fonksiyonlarla değerleri değiştirip tekrar ekrana yazdırdık.Son olarakta başka bir nesne oluşturduk ve bu sefer parametreli yapılandırıcıyı kullandık.Böylece sınıfın değişkenlerine girdiğimiz değerler atanmış oldu.

Son olarak değinmek istediğim bir konu daha var.Yapılandırıcıyı eğer parametreli yaptıysanız ve default olan yapılandırıcıyı yazmadıysanız derleyici bunun yapılandırıcısı var madem ben yazmam der.Eğer siz nesne oluştururken yukarıdaki student nesnesini oluşturduğumuz gibi yani parametre almadan oluşturursanız program default yapılandırıcı yok diye hata verir.Bu durum tam tersi içnde geçerlidir.Yani sadece default var ama siz nesne oluştururken parametre girerseniz bu seferde parametreli yapılandırıcı yok diye hata verecektir.

Yukarıdaki programımızın çıktısınız da verip yazımı sonlandırıyorum.Herkese iyi çalışmalar :)








METOT AŞIRI YÜKLEME(METHOD OVERLOADING)

Method overloading ,bir sınıf içerinde aynı işleve sahip fonksiyonların yine aynı isimli fakat parametre sayısı,türü ya da fonksiyonun dönüş tipi değiştirilerek kullanılmasıdır.Genel tanım budur.Ne demek istedim peki?Örnek üzerinden açıklayayım.

 Yandaki kodda Sum classı altında aynı işlevi gören yani girilen sayıları toplayan üç fonksiyonumuz var.İsimlerini değiştirmeden bu fonksiyonları kullandım ama dikkat edilmesi gereken konu şu ki ilk fonksiyonda dönüş tipim int , parametre sayım iki ve tipi int;ikinci fonksiyona baktığımızda ise yine aynı isimli,dönüş tipi int fakat parametre sayısı üçtür.Yani isimler ve kullanış amacı aynıdır ama parametre sayıları farklıdır.En altta hatalı kullanım olan bir bölüm vardır.Derleyici hata verir çünkü aynı özelliklere sahip zaten bir fonksiyon vardır.
Özetle ben bir fonksiyonun ismini değiştirmeden dönüş tipi,parametre sayısı ya da parametrelerin dönüş tipinden en az birini farklı yaparak kullanabilirim.


Programımızın uygulama kısmında ise her add fonksiyonunu çağırıp farkı görmüş olduk.
Method overloading , çok fazla karmaşık programlarda aynı işlevi olan fonksiyonlara farklı isim verip isim karmaşası yaşatmaktan kurtarır.
















Herkese iyi çalışmalar :)

1 Şubat 2013 Cuma

PAKET(PACKAGE) NEDİR?


Java öğrenirken karşımıza en çok  paket ve import yapıları çıkacaktır .Yeni başlayanlar için oldukça yabancı terimler olabilir benim içinde öyleydi.Ancak ilk öğrendiğiniz dil java değil ve az da olsa c++ ya da c# biliyorsanız anlamanız oldukça kolay olacaktır.Gelin artık başlayalım.

PAKET(PACKAGE)
Java dilinde oldukça fazla sınıf vardır.Sınıflar paket klasörleri içinde yer alan dosyalardır.Mantıksal olarak bağlantısı olan ya da başka bir deyişle birbiriyle ilişkili sınıflar aynı paket içerinde yer almaktadırlar.
(C++ dilini öğrenmiş olanlar bunu namespace kavramıyla bağdaştırmıştır.)Paket tanımı java.paketAdı.sınıfAdı  şeklinde olur.
import ise sınıfı tanımlar.Yani eğer aynı pakette olmayan bir sınıf kullanılmak istenirse önce
sınıfın import edilmesi gerekmektedir.(C++ dilindeki using kelimesiyle benzerdir.)Kullanımı  import  java.paketAdı.sınıfAdı;
Bazen sınıfAdı yerine * işareti ile karşılaşabilirsiniz.Kullanımı şu şekildedir.
import java.paketAdı.*;  Bu,java.paketAdı paketindeki tüm sınıfları çağırabilirsin demektir.

Anlattıklarımızı basit bir uygulama üzerinde görelim...

Yanda ilk_adim adlı projemizin ,oluşturduğum 3 paketi ve her birinin de bir alt birimi yani sınıfı vardır.Sınıflar yani kaynak kodlarımız .java uzantılı dosyada bulunmaktadır.Aslında burada göstermek istediğim  paket kullanımın amacıdır.Yazdığım aynı isimli ve aynı amaçlı metotların farklı paketler aracılığıyla isim değişikliği yapmadan ve karışıklık olmadan kullanabiliriz.Tek yapmamız gereken hangi paketteki metodu kullanacağımızı belirtmektir.






Yukarıda ilk iki paketimizin içindeki sınıfların içerdiği metotlar yer almaktadır.İki pakette aynı görevi gören ve aynı isimli metotları kullanmaktadır.(Resimleri büyütmek için üzerine tıklayın.)


Buda Test_package adlı  main sınıfımızı içeren son paketimiz.package_1 ve package_2 paketlerimizi import ettim çünkü main kısmında sum() ve print() fonksiyonlarını kullanmadık.Yani bu iki fonksiyonumuzda Test_package paketinde yer almadığı için iki paketi de import etmek zorundayım aksi halde o paketlerin metotlarını kullanamam.
Başka bir nokta ise hangi sınıfın metodunu çağırmak istiyorsak o sınıfın  adını kullandığımıza dikkat edelim.Bu şekilde aynı görevi gören metotları farklı isim kullanarak isim karmaşasına neden olmadan programımı yazdım Bu durum belki böylesine basit bir program için size çok mantıklı gelmeyebilir ancak büyük projelerde oldukça kullanışlıdır.





Son olarak işte program çıktımız...








Herkese iyi çalışmalar... :)