Groovy学習ノート(3):インタフェース、ブール判断、オペレータリロード

8826 ワード

Groovyインタフェース


Groovyは、newによって匿名の内部クラスを作成するインスタンスを表示する必要はありません.
//Button 
class Button {

    void addOnClickListener(OnClickListener listener) {
        listener.onClick()
    }

    void addOnLongClickListener(OnLongClickListener listener) {
        listener.onLongClick()
    }

}

// 
interface OnClickListener {
    void onClick()
}
// 
interface OnLongClickListener {
    void onLongClick()
}

addOnClickListenerメソッドが呼び出され、同時にこのメソッドにコードブロックが提供され、asオペレータによってOnClickListenerインタフェースが実現されたことに相当する.
def button = new Button()

listener = { println 'addListener' }

button.addOnClickListener(listener) as OnClickListener

出力:
addListener
Groovyは残りの仕事を自分で処理します.インタフェース内の任意のメソッドの呼び出しをブロックし、呼び出しを提供するコードブロックにルーティングします.
複数のメソッドがあるインタフェースの場合、すべてのメソッドに同じ実装を提供する場合は、上記と同様に、特別な操作は必要ありません.
def button = new Button()

listener = { println 'addListener' }

button.addOnClickListener(listener) as OnClickListener
button.addOnLongClickListener(listener) as OnLongClickListener

出力:
addListener addListener
Groovyにはインタフェース内のすべてのメソッドが強制的に実装されていません.他のメソッドを考慮せずに、自分の関心を定義することができます.残りのメソッドが呼び出されない場合は、これらのメソッドを実装する必要はありません.この技術は,セルテストにおいてインタフェースを実装することによっていくつかの挙動をシミュレートする場合に非常に有用である.
しかし、ほとんどの実際の状況では、インタフェース内の各方法は異なる実装を必要とする.心配しないで、Groovyは平らにすることができます.マッピングを作成し、各メソッドの名前をキーとし、メソッドに対応するコード体をキー値とし、簡単なGroovyスタイルを使用して、メソッド名とコードブロックをコロン(:)で区切るだけです.
すべての方法を実現する必要はありません.本当に関心のあるものを実現すればいいだけです.実装されていない方法が呼び出されていない場合、これらの偽のルートを実現するのに精力を浪費する必要はありません.もちろん、提供されていないメソッドが呼び出されると、例外が発生します.
class Button {

    void addOnStateChangeListener(OnStateChangeListener listener) {
        listener.onCreate()
        listener.onStart()
        listener.onStop()
        listener.onDestory()
    }

}

// 
interface OnStateChangeListener {

    void onCreate()

    void onStart()

    void onStop()

    void onDestroy()
}
def onStateChangelistener = [
        onCreate: {
            println 'onCreate'
        },
        onStart : {
            println 'onStart'
        },
        onStop  : {
            println 'onStop'
        }  // 3onDestroy() 
]
button.addOnStateChangeListener(onStateChangelistener as OnStateChangeListener)

結果:

ブール値判定


Javaでは、if文の条件部分は、前の例のif(obj!=null)やif(val>0)などのブール式である必要があります.
Groovyは、ブール値が必要な場所にオブジェクト参照が配置されている場合、その参照がnullであるかどうかを確認すると推定します.nullはfalseとみなされ、null以外の値はtrueとみなされます.
str = 'hello'

if (str) {
    println str
}

結果:
より正確には、式の結果はオブジェクトのタイプにも関係します.たとえば、オブジェクトがjava.util.ArrayListなどのコレクションである場合、Groovyはそのコレクションが空であるかどうかをチェックします.したがって、この場合、式if(obj)は、objがnullでなく、そのセットが少なくとも1つの要素を含む場合にのみtrueとして計算される.
str1 = null
println str1 ? 'str1 is not null' : 'str1 is null'

str2 = [1, 2, 3]
println str2 ? 'str2 is not null' : 'str2 is null'

str3 = []
println str3 ? 'str3 is not null' : 'str3 is null'

結果:
集合クラスは唯一特別に扱われているわけではありません.では、どのようなタイプが特殊に扱われ、Groovyはどのように計算されますか?
を選択します.
真の条件
Boolean
true
Collection
集合は空ではありません
character
値が0でない
CharSequence
長さ0以外
Enumration
hasMoreElements()はtrue
Iterator
hasNext()はtrue
Number
Double値部0
Map
マップは空ではありません
Matcher
少なくとも1つのマッチング
Object[]
長さ0より大きい
その他の参照タイプ
参照はnullではありません
Groovyに組み込まれたブール評価規則を用いるほか,独自のクラスではasBoolean()メソッドを実現することによって独自のブール変換を記述することもできる.

オペレータリロード


Groovyはオペレータのリロードをサポートしており、これを巧みに適用してDSLを作成することができます.
たとえば、Stringクラスのnext()メソッドをマッピングする++オペレータを再ロードできます.
for (ch = 'a'; ch < 'd'; ch++) {
    println ch
}

結果:
a b c
Groovyでは簡潔なfor-each構文も使用できますが、どちらの実装もStringクラスのnext()メソッドを使用しています.
for (ch in 'a'..'c') {
    println ch
}

結果は同じでabcが出力された.
コレクションに要素を追加するには<
list = ['hello']
list << 'groovy!'
println list

出力:
[hello, groovy!]
マッピングメソッドを追加することで、+オペレータにplus()メソッドを追加するなど、独自のクラスにオペレータを提供できます.
class B03ComplexNumber {

    def real, imaginary // , 

    def plus(other) {
        new B03ComplexNumber(real: real + other.real,
                imaginary: imaginary + other.imaginary)
    }

    @Override
    String toString() {
        return "$real ${imaginary > 0 ? '+' : ''} ${imaginary}i "
    }
}

このコードを実行します.
c1 = new B03ComplexNumber(real: 1, imaginary: 4)
c2 = new B03ComplexNumber(real: 2, imaginary: 3)
println c1 + c2

出力:
3 + 7i
ComplexNumberクラスは+オペレータを再ロードしました.負数平方根に関する複雑な方程式を計算するには,複素数に実部と虚部があることが非常に有用である.ComplexNumberクラスにplus()メソッドを追加したので、+オペレータを使用して2つの複素数を加算し、結果としてもう1つの複素数を得ることができます.