關於java多繼承和mixin實現(轉)


因為工作需要,最近在學習Java,跟Python相比,編碼復雜度高了不少。Java語言語法多,一大堆概念,很些地方的設計與Python相比,實在是太糟糕,強烈建議改進,改進后能大大降低程序的復雜度。

第一點:Java中定義了抽象類和接口,之所有定義接口這個概念,我感覺跟Java的類是單繼承有一定關系,使用接口,可以一定程度上實現多繼承的功能。而Python支持多繼承,

就不必有接口的概念。在Java中實現多繼承和Mixin模式時,要復雜的多。而Python在語言設計上解決了這個問題。

第二點:Java的函數不支持默認參數,而是通過overload的方式,這種方法的復雜度遠比默認參數高。而Python,甚至C++都支持默認參數。

原文:https://blog.csdn.net/wusj3/article/details/80360877

接口是對動作的抽象,抽象類是對根源的抽象。
抽象類表示的是,這個對象是什么。接口表示的是,這個對象能做什么。比如,男人,女人,這兩個類(如果是類的話……),他們的抽象類是人。說明,他們都是人。
人可以吃東西,狗也可以吃東西,你可以把“吃東西”定義成一個接口,然后讓這些類去實現它.


Mixin 實質上是利用語言特性(比如 Ruby 的 include 語法、Python 的多重繼承)來更簡潔地實現組合模式

以如下 Java 偽碼為例,實現一個可復用的“打標簽”組件(Taggable),並且應用到帖子(Post)模型上:
import java.util.List;
import java.util.ArrayList;
 
interface Entity {
    public int getId();
    public int getKind();
}
 
interface Taggable {
    public void addTag(int tagId);
    public List<Integer> getTags();
}
 
class TaggableImpl implements Taggable {
    private Entity target;
 
    public TaggableImpl(Entity target) {
        this.target = target;
    }
 
    public void addTag(int tagId) {
        int id = target.getId();
        int kind = target.getKind();
        System.out.println("insert into ... values "
                + id + ", "
                + kind + ", "
                + tagId + ")");
    }
 
    public ArrayList<Integer> getTags() {
        // query from database
        return new ArrayList<Integer>();
    }
}
 
class Post implements Entity, Taggable {
    public final static int KIND = 1001;
 
    private Taggable taggable;
    private int id;
    private String title;
 
    public Post(int id, String title) {
        this.id = id;
        this.title = title;
        this.taggable = new TaggableImpl(this);
    }
 
    public int getId() {
        return id;
    }
 
    public int getKind() {
        return KIND;
    }
 
    public void addTag(int tagId) {
        taggable.addTag(tagId);  // delegate
    }
 
    public ArrayList<Integer> getTags() {
        return taggable.getTags();  // delegate
    }
}

這里使用組合模式,在 TaggableImpl 中實現打標簽的邏輯,然后讓 Post 類和 TaggableImpl 類都實現 Taggable 接口,Post 類中創建一個 TaggableImpl 實例並在實現 Taggable 時將相應方法調用委托過去。

如果在 Python 中應該怎么做呢?因為 Python 允許多重繼承,所以“委托方法”的過程可以簡化為直接將實現混入宿主類中:

class TagMixin(object):
 
    def add_tag(self, tag_id):
        sql = ('insert into target_tagged'
               ' (target_id, target_kind, tag_id, creation_time) '
               'values (?, ?, ?, CURRENT_TIMESTAMP)')
        params = (self.ident, self.kind, tag_id)
        storage.execute(sql, params)
        storage.commit()
 
    def get_tags(self):
        sql = ('select tag_id, creation_time from target_tagged '
               'where target_id = ? and target_kind = ?')
        params = (self.ident, self.kind)
        cursor = storage.execute(sql, params)
        return cursor.fetchall()
 
 
class Post(Model, TagMixin):
 
    kind = 1001
 
    def __init__(self, ident, title):
        self.ident = ident
        self.title = title
 
    def __repr__(self):
        return 'Post(%r, %r)' % (self.ident, self.title)

可以看出這里多重繼承的用法是非常謹慎的:

  • TagMixin 類是單一職責的
  • TagMixin 類對宿主類(Post)一無所知,除了要求宿主類有 ident 和 kind 這兩個屬性(等價於 Java 中要求宿主類實現 Entity 接口)
  • 宿主類的主體邏輯不會因為去掉 TagMixin 而受到影響,同時也不存在超類方法調用(super)以避免引入 MRO 查找順序問題

所以這樣比 Java 中的組合模式實現方式更加簡潔。同時因為使用得當,鑽石調用、MRO 查找順序等多重繼承的弊病也沒有被踩到。當然,這種 Duck Type 的設計也比顯式的接口約束對開發者有更高的要求,要求代碼中無 interface 而開發者腦海中有清晰的 interface。

Ruby 的 include 語法實現的 Mixin 也同理。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM