2016-04-20 28 views
11

Tôi đang cố gắng hiểu Mixins trong bối cảnh scala. Đặc biệt, tôi muốn biết sự khác biệt giữa các khái niệm về thừa kế và Mixins. Wiki nói rằng có sự khác biệt quan trọng giữa các khái niệm về mixin và thừa kế và do đó tôi muốn hiểu nó.Sự khác biệt giữa mixin và thừa kế là gì?

Định nghĩa của Mixin trong wiki nói:

Một lớp mixin hoạt động như lớp cha mẹ, có chứa các chức năng mong muốn. Sau đó, một lớp con có thể kế thừa hoặc đơn giản sử dụng lại chức năng này, nhưng không phải là phương tiện chuyên môn. Thông thường, mixin sẽ xuất các chức năng mong muốn vào một lớp con, mà không tạo ra một mối quan hệ cứng nhắc, duy nhất "là một". Đây là sự khác biệt quan trọng giữa các khái niệm về mixin và thừa kế, trong đó lớp con vẫn có thể kế thừa tất cả các đặc tính của lớp cha, nhưng, ngữ nghĩa về đứa trẻ "là một loại" cha mẹ không nhất thiết phải áp dụng.

Trong định nghĩa trên, tôi không thể hiểu các câu được đánh dấu bằng chữ in đậm. điều đó có nghĩa là

  1. Một lớp có thể kế thừa chức năng trong mixin nhưng không phải là một phương tiện để chuyên môn hóa
  2. Trong mixins, đứa trẻ được thừa hưởng tất cả các tính năng của lớp cha nhưng ngữ nghĩa về trẻ em "là một loại" các cha mẹ không cần thiết phải được áp dụng. - Làm thế nào một đứa trẻ có thể mở rộng một phụ huynh và không nhất thiết phải là một loại Phụ Huynh? Có một ví dụ như thế.

Cảm ơn trước vì đã giải thích rõ về điều này.

+0

Trong Scala, hãy nghĩ về Mixins như một phép biến đổi biên dịch thời gian gọn gàng, nó sẽ trang trí một số loại nhất định với các phương thức bổ sung. Trong trường hợp này, trong khi Scala theo dõi "hỗn hợp trong các loại" cho trình kiểm tra kiểu, các định nghĩa phương thức tự được * làm phẳng * thành các kiểu thực tế để không có cha-con được thiết lập trong các lớp JVM. Thừa kế thường được kết hợp với độ phân giải phương pháp đa hình thời gian chạy - nhưng mixin là (chủ yếu) khái niệm trực giao. Giao diện Java 8 Các phương thức mặc định là các mixin. – user2864740

+0

Câu hỏi này dường như đã được [hỏi trước trong một bối cảnh rộng hơn] (http://stackoverflow.com/questions/860245/mixin-vs-inheritance) (mặc dù tôi không cảm thấy hoàn toàn hài lòng bởi các câu trả lời ở đó). – badcook

Trả lời

7

Tôi không chắc tôi đã hiểu câu hỏi của bạn đúng cách, nhưng nếu tôi đã làm, bạn đang hỏi làm thế nào một cái gì đó có thể kế thừa mà không thực sự có ý nghĩa giống như kế thừa.

Mixins, tuy nhiên, không phải là thừa kế - nó thực sự tương tự như tự động thêm một tập hợp các phương thức vào một đối tượng. Trong khi thừa kế nói "Cái này là một thứ khác", mixin nói, "Vật thể này có một số đặc điểm của thứ khác này." Bạn có thể thấy điều này trong từ khóa được sử dụng để khai báo kết hợp: trait.

Để ngang nhiên ăn cắp một ví dụ từ trang chủ Scala:

abstract class Spacecraft { 
    def engage(): Unit 
} 
trait CommandoBridge extends Spacecraft { 
    def engage(): Unit = { 
    for (_ <- 1 to 3) 
     speedUp() 
    } 
    def speedUp(): Unit 
} 
trait PulseEngine extends Spacecraft { 
    val maxPulse: Int 
    var currentPulse: Int = 0 
    def speedUp(): Unit = { 
    if (currentPulse < maxPulse) 
     currentPulse += 1 
    } 
} 
class StarCruiser extends Spacecraft 
        with CommandoBridge 
        with PulseEngine { 
    val maxPulse = 200 
} 

Trong trường hợp này, StarCruiser không phải là một CommandoBridge hoặc PulseEngine; nó chúng, mặc dù, và đạt được các phương pháp được xác định trong những đặc điểm đó. Nó a Spacecraft, như bạn có thể thấy vì nó được kế thừa từ lớp đó.

Điều đáng nói đến là khi một số trait kéo dài class, nếu bạn muốn tạo một đặc điểm with, nó phải mở rộng lớp đó. Ví dụ: nếu tôi có số class Dog, tôi không thể có số Dog with PulseEngine trừ khi Dog mở rộng Spacecraft. Theo cách đó, nó không hoàn toàn giống như thêm phương thức; tuy nhiên, nó vẫn tương tự.

1

Tôi nghĩ rằng nó đang nói về thứ bậc lớp thực tế. Ví dụ: Dog là loại Animal nếu nó kéo dài từ lớp (kế thừa). Nó có thể được sử dụng bất cứ nơi nào một tham số Animal được áp dụng.

2

Một đặc điểm (được gọi là mixin khi trộn với một lớp học) giống như một giao diện trong Java (mặc dù có rất nhiều differences), nơi bạn có thể thêm các tính năng bổ sung cho một lớp học mà không nhất thiết phải "là một" mối quan hệ. Hoặc bạn có thể nói rằng nói chung là các đặc điểm kết hợp các tính năng có thể được nhiều lớp độc lập sử dụng.

Để cung cấp cho bạn một ví dụ từ thư viện Scala, Ordered[A] là một trait cung cấp thực hiện đối với một số hoạt động so sánh cơ bản (như <, <=, >, >=) đến các lớp học có thể có dữ liệu với trật tự tự nhiên. Ví dụ:

Ví dụ: giả sử bạn có lớp của riêng mình Number và các lớp con EvenNumberOddNumber như được hiển thị bên dưới.

class Number(val num : Int) extends Ordered[Number] { 
    override def compare(that : Number) = this.num - that.num 
} 

trait Half extends Number { 
    def half() = num/2 
} 

trait Increment extends Number { 
    def increment() = num + 1 
} 

class EvenNumber(val evenNum : Int) extends Number(evenNum) with Half 

class OddNumber(val oddNum : Int) extends Number(oddNum) with Increment 

Trong ví dụ trên, các lớp học EvenNumberOddNumber phần là một mối quan hệ với Number nhưng EvenNumber không có "là một" mối quan hệ với Half không OddNumber chia sẻ "là một" mối quan hệ với Increment.

Một điểm quan trọng là mặc dù lớp Number sử dụng extends Ordered cú pháp, nó có nghĩa là Numberngầmlà một mối quan hệ với lớp cha của Ordered tức Any.

2

Tôi nghĩ rằng việc sử dụng rất phụ thuộc của nó. Scala là một ngôn ngữ đa mô hình làm cho nó mạnh mẽ cũng như một chút bối rối ở lần. Tôi nghĩ Mixins rất mạnh mẽ khi sử dụng đúng cách. Mixins nên được sử dụng để giới thiệu hành vi và giảm bolierplate.

Một đặc điểm trong Scala có thể có triển khai và rất hấp dẫn để mở rộng và sử dụng chúng.

Các đặc điểm có thể được sử dụng để kế thừa. Nó cũng có thể được gọi là mixins tuy nhiên theo ý kiến ​​của tôi không phải là cách tốt nhất để sử dụng hành vi mixin. Trong trường hợp này, bạn có thể nghĩ đến các đặc điểm như các lớp trừu tượng Java. Trong đó bạn nhận được các lớp con là "loại" lớp siêu (đặc điểm).

Tuy nhiên, Đặc điểm cũng có thể được sử dụng làm proper mixins. Bây giờ sử dụng một đặc điểm như là một mixin phụ thuộc vào việc thực hiện đó là "cách bạn trộn nó vào". Chủ yếu là một câu hỏi đơn giản để tự hỏi mình. Đó là "Là phân lớp của đặc điểm thực sự là một kind của đặc điểm hoặc là những hành vi trong các hành vi đặc điểm làm giảm boilerplate". Thông thường nó được thực hiện tốt nhất bằng cách trộn các đặc điểm với các đối tượng thay vì mở rộng đặc điểm để tạo các lớp mới.

Ví dụ xem xét ví dụ sau:

//All future versions of DAO will extend this 
trait AbstractDAO{ 
    def getRecords:String 
    def updateRecords(records:String):Unit 
} 
//One concrete version 
trait concreteDAO extends AbstractDAO{ 
    override def getRecords={"Here are records"} 
    override def updateRecords(records:String){ 
    println("Updated "+records) 
    } 
} 
//One concrete version 
trait concreteDAO1 extends AbstractDAO{ 
    override def getRecords={"Records returned from DAO2"} 
    override def updateRecords(records:String){ 
    println("Updated via DAO2"+records) 
    } 
} 
//This trait just defines dependencies (in this case an instance of AbstractDAO) and defines operations based over that 
trait service{ 
    this:AbstractDAO => 

    def updateRecordsViaDAO(record:String)={ 
    updateRecords(record) 
    } 
    def getRecordsViaDAO={ 
    getRecords 
    } 
} 


object DI extends App{ 
    val wiredObject = new service with concreteDAO //injecting concrete DAO to the service and calling methods 
    wiredObject.updateRecords("RECORD1") 
    println(wiredObject.getRecords) 

    val wiredObject1 = new service with concreteDAO1 
    wiredObject1.updateRecords("RECORD2") 
    println(wiredObject1.getRecords) 

} 

concreteDAO là một đặc điểm mà kéo dài AbstractDAO - Đây là kế thừa

val wiredObject = new service with concreteDAO - này được thích hợp mixin hành vi Kể từ khi đặc điểm dịch vụ ủy thác cho mixin của a AbstractDAO. Nó sẽ là sai cho Service để mở rộng ConcreteDAO anyways vì service yêu cầu AbstractDAO nó không phải là một loại AbstractDAO. Thay vào đó, bạn tạo các phiên bản service với các mixin khác nhau.

Các vấn đề liên quan