因為工作需要,最近在學習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 也同理。