بررسی اینترفیس ها
اینترفیس ها شبه کلاس هستند و متدهای رایج در آبجکت ها رو داخل اینترفیس ها تعریف میکنیم.
اینترفیس (interface) ها در جاوا برای تعریف متد های رایج بین کلاس ها و یا مقادیر ثابت استاتیک مورد استفاده قرار میگیرند.
در اینترفیس ها نمیتونیم کانستراکتور تعریف کنیم و ازشون نمونه (آبجکت) ایجاد کنیم.
فرم کلی:
برای ارث بردن از اینترفیس ها از کلیدواژه extends بعد از اسم اینترفیس استفاده میکنیم.
interface Foo extends Bar{
...
}
interface Bar{
...
}
هر اینترفیس میتونه از یک یا چند اینترفیس دیگه ارث ببره.
interface Foo extends Bar, Baz, Qux{
...
}
interface Bar{
...
}
interface Baz{
...
}
interface Qux{
...
}
تنها فیلد هایی که میتونیم داخل یک اینترفیس تعریف کنیم فیلد های public static final است.
interface Foo{
public static final int MY_STATIC_CONSTANT = 1;
}
در اینترفیس ها متد های وابسته به آبجکت رو فقط میتونیم به صورت ابستراکت تعریف کنیم و اگه بخوایم یک متد کامل داخل اینترفیس تعریف کنیم باید متد استاتیک و با سطح دسترسی private یا public باشه. یا متد default با سطح دسترسی public.
interface Foo{
//متد ابستراکت
public void bee();
//متد کامل استاتیک
public static void boo(){
System.out.println("Hello Foo!");
}
}
توجه
متد های ابستراکت در اینترفیس ها به طور پیشفرض ابستراکت و public هستند بنابراین نیاز به نوشتن کلیدواژه های abstract و public هنگام تعریف متد های ابستراکت در اینترفیس نیست.
از اینترفیس ها میتونیم به عنوان نوع متغیر نیز استفاده کنیم.
فرض کنید MyClass از MyInterface رو در خودش پیادهسازی کرده؛ یک متغیر از نوع MyInterface میتونه به یک آبجکت از کلاس اشاره کنه.
MyInterface obj = new MyClass();
پیادهسازی اینترفیس ها در کلاس
یک کلاس همزمان میتونه از یک کلاس دیگه ارث ببره چند اینترفیس رو داخلش پیادهسازی کنه.
هنگامی که یک اینترفیس رو داخل کلاس پیادهسازی میکنیم باید تمام متد های ابستراکت در اینترفیس رو داخل کلاس بازنویسی کنیم؛ اگه کلاس ابستراکت باشه نیاز نداریم متد های اینترفیس رو بازنویسی کنیم.
با استفاده از کلید واژه ی implements میتونیم یک یا چند اینترفیس رو در کلاس پیادهسازی کنیم.
public class Foo extends Bar implements Baz, Qux{
...
}
class Bar{
...
}
interface Baz {
...
}
مثال
فرض کنید یک کلاس MusicPlayer داریم و میخوایم عملیات Play، Pause و Stop اینترفیس Player رو داخلش پیادهسازی کنیم.
public class MusicPlayer implements Player{
@Override
public void Play(){
System.out.println("Playing...");
}
@Override
public void pause(){
System.out.println("Pausing...");
}
@Override
public void stop(){
System.out.println("Stopping...");
}
@Override
public void next(){
System.out.println("Next..");
}
}
interface Player{
void play();
void pause();
void stop();
void next();
}
public static void main(String[] args){
Player player = new MusicPlayer();
player.play();
}
بررسی Comparable
اینترفیس Comparable دارای یک متد به اسم compareTo است که دو آبجکت رو با همدیگه مقایسه میکنه.
اینترفیس Comparable یکی از اینترفیس های تعریف شده در java.lang است؛ از Comparable برای مقایسه ی دوتا آبجکت استفاده میکنیم.
متد compareTo(T) بری بررسی دو نوع از جنس همدیگه مورد استفاده قرار میگیره اگه ویژگی هایی که هردو آبجکت دارن یکسان بود طبق قرارداد مقدار 0 رو بر میگردونیم؛ اگه آبجکتی که متد داخلش پیاده شده ویژگیش به لحاظ عددی بزرگتر بود مقدار 1 و اگه کوچیکتر بود مقدار -1 رو برمیگردونیم.
مثال
در مثال زیر میخوایم از Comparable در کلاس GeometricShape ارث بری کنیم؛ با اینکه GeometricShape ابستراکت است ولی میتونیم متد compareTo رو در خود GeometricShape پیادهسازی کنیم.
public abstract class GeometricShape implements Comparable<GeometricShape>{
private final Date dateCreated = new Date();
private String color;
private boolean filled;
public GeometricShape(String color, boolean filled){
this.color = color;
this.filled = filled;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Date getDateCreated() {
return dateCreated;
}
public boolean isFilled() {
return filled;
}
public void setFilled(boolean filled) {
this.filled = filled;
}
public abstract double getPerimeter();
public abstract double getArea();
//پیاده سازی compareTo در Comparable
@Override
public int compareTo(GeometricShape o) {
if (o.getArea() < this.getArea())
return 1;
else if (o.getArea() > this.getArea())
return -1;
else
return 0;
}
@Override
public String toString() {
if(this instanceof Circle)
return "Circle: created on " + getDateCreated().toString() + "\n" + " area: " + getArea() + " perimeter " + getPerimeter();
else
return "Rectangle: created on " + getDateCreated().toString() + "\n" + " area: " + getArea() + " perimeter: " + getPerimeter();
}
}
class Circle extends GeometricShape{
private double radius;
public Circle(double radius, String color, boolean filled){
super(color, filled);
this.radius = radius;
}
public Circle(double radius){
this(radius, "white", false);
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getArea(){
return Math.PI * radius * radius;
}
public double getPerimeter(){
return 2 * Math.PI * radius;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Circle)
return ((Circle) obj).radius == this.radius;
return false;
}
}
class Rectangle extends GeometricShape{
private double width;
private double height;
public Rectangle(double width , double height, String color, boolean filled){
super(color, filled);
this.width = width;
this.height = height;
}
public Rectangle(){
this(1.0, 1.0, "White", true);
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public double getArea(){
return width * height;
}
@Override
public double getPerimeter(){
return (width + height) * 2;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Rectangle){
Rectangle r = (Rectangle) obj;
return r.width == this.width && r.height == this.height;
}
return false;
}
}
public static void main(String[] args){
GeometricShape circle = new Circle(4, "Blue", true);
GeometricShape rectangle = new Rectangle(5, 3, "Red", true);
GeometricShape rectangle1 = new Rectangle(5, 3, "Black", false);
System.out.println(circle.compareTo(rectangle));
System.out.println(circle.compareTo(rectangle1));
System.out.println(rectangle.compareTo(rectangle1));
}
اینترفیس های تابعی
اینترفیس هایی که فقط یک متد دارند و به عنوان پارامتر یک متد تعریف شده باشند رو میتونیم به صورت عبارت لامبدا پیاده سازیشون کنیم.
یکی از موارد معروف از این مورد متد setOnClickListener در کلاس View اندروید است که در مثال زیر نشون میده چطور کار میکنه.
public class View {
public void setOnClickListener(OnClickListener listener){
listener.onClick(this);
}
public interface OnClickListener{
void onClick(View view);
}
}
استفاده از اینترفیس به عنوان پارامتر متد.
public static void main(String[] args){
View v = new View();
v.setOnClickListener(v -> System.out.println("clicked!"))
}
چون در مثال بالا برنامه منتظر کلیک کاربر نیست با اجرای کد عبارت clicked اجرا میشه.
مورد مطالعه (مثال ها)
فرض کنید میخوایم برای گوشت و میوه اینترفیسی طراحی کنیم که در میوه ها پیادهسازی بشه و فقط گوشت هایی که قابل خوردن هستند پیاده سازیش کنن.
interface Edible {
public abstract String howToEat();
}
abstract class Animal {
private double weight;
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public abstract String sound();
}
class Chicken extends Animal implements Edible {
@Override
public String howToEat() {
return "Chicken: Fry it";
}
@Override
public String sound() {
return "Chicken: cock-a-doodle-doo";
}
}
class Tiger extends Animal {
@Override
public String sound() {
return "Tiger: RROOAARR";
}
}
abstract class Fruit implements Edible {
//چون همه ی میوه ها خوراکی هستند یک کلاس ابستراکت به اسم میوه به عنوان کلاس بیس برای تمام کلاس های میوه طراحی کردیم.
}
class Apple extends Fruit {
@Override
public String howToEat() {
return "Apple: Make apple cider";
}
}
class Orange extends Fruit {
@Override
public String howToEat() {
return "Orange: Make orange juice";
}
}
public static void main(String[] args) {
Object[] objects = {new Tiger(), new Chicken(), new Apple()};
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof Edible)
System.out.println(((Edible)objects[i]).howToEat());
if (objects[i] instanceof Animal) {
System.out.println(((Animal)objects[i]).sound());
}
}
}
خلاصه
- از اینترفیس ها نمیتونیم نمونه ایجاد کنیم و همینطور نمیتونیم داخل اینترفیس کانستراکتور تعریف کنیم.
- در اینترفیس ها فقط میتونیم متد های ثابت استاتیک با دسترسی public و private و همچنین متد های default با دسترسی public رو به صورت کامل تعریف کنیم.
- متد های وابسته به آبجکت در اینترفیس ها ابستراکت هستند و دسترسی public باید داشته باشند.
- در اینترفیس ها تنها فیلد های ثابت استاتیک با دسترسی public رو میتونیم تعریف کنیم.
- یک اینترفیس میتونه از چند اینترفیس همزمان ارث بری کنه.
- یک کلاس میتونه همزمان از یک کلاس دیگه ارث بری کنه و چند اینترفیس رو پیادهسازی کنه.