用Java中的抽象类扩展抽象类
示例問題
當(dāng)我創(chuàng)建Java :: Geci抽象類AbstractFieldsGenerator和AbstractFilteredFieldsGenerator我遇到了一個(gè)不太復(fù)雜的設(shè)計(jì)問題。 我想強(qiáng)調(diào)一下,對于某些人來說,這個(gè)問題和設(shè)計(jì)可能看起來很明顯,但是在我最近與一位初級開發(fā)人員(我的兒子Mihály的交談)中,我的文章比我的英語要好得多,意識到這個(gè)話題可能仍然有價(jià)值。
無論如何。 我有這兩個(gè)類,字段和過濾字段生成器。 第二堂課擴(kuò)展了第一堂課
abstract class AbstractFilteredFieldsGenerator extends AbstractFieldsGenerator {...添加額外的功能,同時(shí)應(yīng)為具體實(shí)現(xiàn)提供相同的簽名。 這是什么意思?
這些生成器有助于使用反射為特定類生成代碼。 因此,他們處理的輸入信息是Class對象。 字段生成器類具有一個(gè)抽象方法process() ,該方法將為每個(gè)字段調(diào)用。 它是從一個(gè)實(shí)現(xiàn)的方法調(diào)用的,該方法遍歷字段并分別對每個(gè)字段進(jìn)行調(diào)用。 當(dāng)具體類extends AbstractFieldsGenerator并由此實(shí)現(xiàn)此抽象方法時(shí),它將被調(diào)用。 當(dāng)更改相同的具體類以使其extends AbstractFilteredFieldsGenerator ,將僅對過濾后的方法調(diào)用具體方法。 我想要一個(gè)設(shè)計(jì),以便在具體課程中唯一需要的更改是更改名稱。
問題定義 類
以更抽象的方式描述相同的問題:有兩個(gè)抽象類A和F以便F extends A和F提供一些額外的功能。 兩者都聲明了具體類應(yīng)實(shí)現(xiàn)的抽象方法m() 。 當(dāng)具體的類C聲明從C extends A到C extends F到C extends F時(shí),方法m()的調(diào)用應(yīng)更改,但類C不應(yīng)有其他更改。 從類A定義的方法p()調(diào)用方法m() 。 如何設(shè)計(jì)F ?
這是什么問題?
可以通過兩種明顯不同的方式來擴(kuò)展A :
- F覆蓋m()使它混凝土在實(shí)施額外的功能m()并調(diào)用新的抽象方法,說mx()
- F使用提供額外功能的版本覆蓋方法p() (在上面的示例中進(jìn)行過濾),并調(diào)用仍然抽象的方法m()
第一種方法不能滿足由具體類C實(shí)施的簽名應(yīng)保持相同的要求。 第二種方法將A的已經(jīng)實(shí)現(xiàn)的功能扔到垃圾桶上,并以不同的方式重新實(shí)現(xiàn)它。 在實(shí)踐中這是可能的,但是肯定會進(jìn)行一些復(fù)制/粘貼編程。 這是有問題的,讓我不解釋原因。
問題的根源
在工程中,當(dāng)我們面對這樣的問題時(shí),通常意味著問題或結(jié)構(gòu)沒有得到很好的描述,解決方案位于完全不同的區(qū)域中。 換句話說,有些假設(shè)驅(qū)動我們的思維方式是錯(cuò)誤的。 在這種情況下,問題在于我們假設(shè)抽象類提供了一個(gè)擴(kuò)展“ API”來對其進(jìn)行擴(kuò)展。 請注意,API不僅可以調(diào)用。 對于抽象類,擴(kuò)展該抽象類時(shí)要實(shí)現(xiàn)的API。 正如庫可以為不同的使用方式提供不同的API(Java 9 HTTP客戶端可以send()以及sendAsync() )抽象(實(shí)際上也是非抽象的)類也可以提供不同的擴(kuò)展方式用于不同的目的。
如果不修改A就無法編碼F達(dá)到我們的設(shè)計(jì)目標(biāo)。 我們需要一個(gè)A版本,該版本提供不同的API來創(chuàng)建具體的實(shí)現(xiàn),而另一個(gè)版本(不一定要是正交的)可以創(chuàng)建一個(gè)仍然抽象的擴(kuò)展。
在這種情況下,API之間的區(qū)別在于,具體實(shí)現(xiàn)的目標(biāo)是在調(diào)用鏈的末尾,而抽象擴(kuò)展要掛接到鏈的最后一個(gè)元素。 A的實(shí)現(xiàn)必須提供要掛接到調(diào)用鏈的最后一個(gè)元素上的API。 這已經(jīng)是解決方案。
解
我們在類F實(shí)現(xiàn)了方法ma() ,我們希望p()調(diào)用ma()而不是直接調(diào)用m() 。 修改A我們可以做到。 我們在A定義ma() ,然后從p()調(diào)用ma() p() 。 在A實(shí)現(xiàn)的ma()版本應(yīng)毫不費(fèi)力地調(diào)用m() ,以為A具體實(shí)現(xiàn)提供原始的“ API”。 F中的ma()實(shí)現(xiàn)包含額外的功能(在示例中為過濾),然后調(diào)用m() 。 這樣,任何具體的類都可以擴(kuò)展A或F并可以使用完全相同的簽名實(shí)現(xiàn)m() 。 我們還避免了復(fù)制/粘貼編碼,只是調(diào)用m()是在ma()的兩個(gè)版本中相同的代碼。
如果我們希望類F具有更多抽象類可擴(kuò)展性,則F::ma實(shí)現(xiàn)不應(yīng)直接調(diào)用m() ,而應(yīng)調(diào)用m()的新mf() m() 。 這樣,新的抽象類可以覆蓋mf()從而再次提供新功能并調(diào)用抽象m() 。
帶走
- 在https://github.com/verhas/abstractchain中找到示例演示應(yīng)用程序
- 在https://github.com/verhas/javageci中找到具有這種模式的原始的,稍微復(fù)雜的應(yīng)用程序
翻譯自: https://www.javacodegeeks.com/2019/06/extending-abstract-classes-with-abstract-classes-in-java.html
總結(jié)
以上是生活随笔為你收集整理的用Java中的抽象类扩展抽象类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 香港回归的时间是几年几月几日 关于香港回
- 下一篇: java8 streams_使用Java