第七章、Groovy物件導向

往前的娘娘發表於2020-12-02

1、定義類和指令碼

1.1、定義成員變數和本地變數

  • 定義成員變數, 本地變數

  • /**
     * 宣告變數
     * @author liangchen* @date 2020/11/8
     */
    class DeclareVariableDemo {
    
        // 成員變數
        public fieldWithModifier
        String typedField
        def untypeField
        protected field1, field2, field3
        private assignedField = new Date()
        static classField
        public static final String CONSTA = 'a', CONSTB = 'b'
    
        static void main(String[] args) {
            // ClassCastException 類轉換異常
            final String PI = '3.14'
            assert PI.class.name == 'java.lang.String'
    
            assert PI.size() == 4
    
            GroovyAssert.shouldFail(ClassCastException) {
                Float areaofCircleRadiusOne = PI
            }
        }
    
        def someMethods(){
            // 本地變數
            def localUntypedMethodVar = 1
    
            int localTypedMethodVar = 1
    
            def localVarWithoutAssigment , andAnotherOne
    
        }
    
        def localvar = 1,boundvar1 = 1
        def someMethod(){
            def localMethodVar = 1
            boundvar2 = 1
        }
    
    
    
    }
    
    
  • 沒有欄位預設呼叫方法

  • /**
     * 引用成員變數
     * @author liangchen* @date 2020/11/8
     */
    class ReferenceFieldDemo {
        static void main(String[] args) {
            def counter = new Counter()
            counter.count = 1
            assert counter.count == 1
    
            def fieldName = 'sum'
            counter[fieldName] = 2
            assert counter.sum == 2
    
            // 沒有值,就呼叫get方法
            def pretender = new PretendFieldCounter()
            assert pretender.isNoField == 'pretend value'
    
            assert pretender.count == 0
            //呼叫set方法 count ==1
            pretender.isNoFieldEither = 'just to increase counter'
            // 呼叫set方法  count==2
            pretender.aaa = 1
            assert pretender.count == 2
        }
    }
    class Counter{
        public count =0
        public sum = 0
    }
    
    class PretendFieldCounter {
        public count = 0
    
        Object get(String name) {
            return 'pretend value'
        }
    
        void set(String name, Object value) {
            count++
    
        }
    }
    
    

1.2、定義方法和引數

  • 可以是確定型別和不確定型別

  • /**
     * 宣告方法 和入參型別
     * @author liangchen* @date 2020/11/8
     */
    class ClassWithTypedAndUntypedMethods {
    
        static void main(args) {
            def some = new ClassWithTypedAndUntypedMethods()
            some.publicVoidMethod()
            assert 'hi' == some.publicUntypedMethod()
            assert 'ho' == some.publicTypeMethod()
            def classWith = new ClassWithTypedAndUntypedMethodParams()
            // 入參型別
            assert 'untyped' == classWith.method(1)
            assert 'typed' == classWith.method('whatever')
            assert  'two args' == classWith.method(1,2)
    
        }
    
    
        /**
         * 沒有返回值
         */
        void publicVoidMethod(){}
    
        /**
         * 沒有返回型別方法
         * @return
         */
        def publicUntypedMethod(){
            return 'hi'
        }
    
        /**
         * 有返回值型別
         * @return
         */
        String publicTypeMethod(){
            return 'ho'
        }
        private static final void combinedMethod(){}
    }
    
    class ClassWithTypedAndUntypedMethodParams {
        static void main(args) {
    
        }
    
        /**
         * 不確定型別入參
         * @param arg
         * @return
         */
        static method(arg){
            return 'untyped'
        }
    
        /**
         * 有型別入參
         * @param arg
         * @return
         */
        static method(String arg) {
            return 'typed'
        }
    
        /**
         * 兩個引數
         * @param arg1
         * @param arg2
         * @return
         */
        static method(arg1, Number arg2) {
            return 'two args'
        }
    }
    
    
  • map, list 陣列入參

    • /**
       * list map 入參
       * @author liangchen* @date 2020/11/9
       */
      class Summer {
      
          static void main(String[] args) {
              def summer = new Summer();
              assert  2 == summer.sumWithDefualts(1,1)
      
              assert 3 == summer.sumWithDefualts(1, 1, 1)
      
              assert 2 == summer.sumWithList([1,1])
              assert 3 == summer.sumWithList([1,1,1])
      
              assert 2 == summer.sumWithOptionals(1,1)
              assert 3 == summer.sumWithOptionals(1,1,1)
      
              assert 2 == summer.sumNamed(a:1, b:1)
              assert 3 == summer.sumNamed(a: 1, b: 1, c: 1)
              assert 1 == summer.sumNamed(c:1)
      
          }
      
          def sumWithDefualts(a, b, c = 0) {
              return a + b + c
      
          }
      
          def sumWithList(List args) {
              return args.inject (0){sum, i -> sum +=i}
          }
      
          def sumWithOptionals(a, b, Object[] optionals) {
              return a + b + sumWithList(optionals.toList())
          }
      /**
       * 入參為map
       * @param args
       * @return
       */
      
          def sumNamed(Map args) {
              // 不存在設定0
              ['a','b','c'].each {args.get(it, 0)}
              return args.a + args.b + args.c
          }
      }
      

1.3、?. 判斷是否連續為空 (短路運算子)

  • 避免連續判空

    • /**
       * ?. 避免空指標,連續判空
       * @author liangchen* @date 2020/11/9
       */
      class ProtectionNPEs {
      
          static void main(String[] args) {
              def map = [a: [b: [c: 1]]]
              assert  map.a.b.c ==1
      
              if (map && map.a && map.a.x) {
                  assert map.a.x.c == null
              }
      
              try {
                  assert map.a.x.c == null
              } catch (NullPointerException ignore) {
      
              }
              assert map?.a?.x?.c==null
          }
      
      }
      
      

1.4、構造器

  • 指定成員變數名和其他方式

    • /**
       * @author liangchen* @date 2020/11/9
       */
      class CallConstructorDemo {
          String name, product
      
          CallConstructorDemo(name, product) {
              this.name = name
              this.product = product
          }
      
          // Java 的方式
          def first = new CallConstructorDemo('Canoo', "ULC")
      
          // as 語法
          def second = ['Canoo','ULC'] as CallConstructorDemo
      
          // 自己陣列元素
          CallConstructorDemo third = ['Canoo', 'ULC']
      }
      
      
      class CallConstructorNameDemo{
          String name, product
      
          public static void main(String[] args) {
              // 可以指定成員變數名
              new CallConstructorNameDemo()
              new CallConstructorNameDemo(name: 'Canoo')
              new CallConstructorNameDemo(product:'ULC')
              new CallConstructorNameDemo(name: 'Canoo', product: 'ULC')
              
          }
      }
      
      

2、組織類和指令碼

2.1、檔案與類關係

  • 一個檔案有多個類

    • /**
       * 一個groovy 有兩個類
       * @author liangchen* @date 2020/11/9
       */
      class MultipleClassDemo {
          static void main(String[] args) {
              def canoo = new Vendor()
              canoo.name = 'jack'
              canoo.product='apple'
              canoo.address.street = '天頂鄉'
              canoo.address.zip = 1121
              canoo.address.town = '嶽麓區'
              canoo.address.state = '長沙'
              // 查詢匹配字元
              assert canoo.dump() =~ /apple/
              // 查詢匹配字元
              assert canoo.address.dump() =~/1121/
              println canoo.address.dump()
          }
      }
      class Vendor {
          public String name
          public String product
      
          public Address address =new Address();
      }
      class Address{
          public String  street, town , state
          public int zip
      }
      
      

2.2、在包組織類

  • 跟java類似

  • 預設匯入語句

    • import java.lang.*
      
      import java.util.*
      
      import java.io.*
      
      import java.net.*
      
      import groovy.lang.*
      
      import groovy.util.*
      
      import java.math.BigInteger
      
      import java.math.BigDecimal
      
      
  • 匯入設定別名 ( 避免相同類名,不同包下,識別更快)

    • 需要繼承類

    • package com.jack.groovy.ch7.thirdparty
      
      /**
       * @author liangchen* @date 2020/11/10
       */
      class MathLib {
      
          Integer twice(Integer value) {
              return value * 3
      
          }
      
          Integer half(Integer value) {
              return value / 2
      
          }
      }
      
      
    • 繼承類

      • package com.jack.groovy.ch7
        
        // 這裡使用 as 為這個匯入設定別名
        import com.jack.groovy.ch7.thirdparty.MathLib as TypeMathLib
        /**
         * @author liangchen* @date 2020/11/10
         */
        class MathLib extends TypeMathLib  {
        
            /**
             * 訂正 2倍
             * @param value
             * @return
             */
            Integer twice(Integer value) {
                return value * 2
        
            }
        
            static void main(String[] args) {
                def mathlib = new MathLib()
                assert 10 == mathlib.twice(5)
                assert  2 == mathlib.half(5)
            }
        
        }
        
        

2.3、考慮更深classpath(類路徑)

3、物件導向的高階特性

3.1、使用繼承

  • 類似java

3.2、使用介面

  • 類似java

3.3、多方法(過載)

  • 方法名一樣,入參不一樣

  • /**
     * 方法過載
     * @author liangchen* @date 2020/11/10
     */
    class Multimethod {
    
        def oracle(Object o) {
            return 'object'
        }
    
        def oracle(String o) {
            return 'string'
        }
    
        static void main(String[] args) {
           def multi =  new Multimethod()
            Object x =1
            Object y = 'foo'
    
            assert 'object' == multi.oracle(x)
    
            assert 'string' == multi.oracle(y)
    
        }
    
    }
    
    
    

3.4、使用trait

  • trait 關鍵字

  • /**
     * trait 有點類似 介面,只不過他有一些方法和屬性, 應該說是抽象類和介面結合體
     * @author liangchen* @date 2020/11/10
     */
    class TraitDemo {
    
        trait HashId{
            long id
        }
    
        trait HasVersion{
            long version
        }
        trait Persistent{
            boolean save(){
                println "saving ${this.dump()}"
            }
        }
    
        trait  Entity implements Persistent ,HashId, HasVersion{
            boolean save(){
                version++
                Persistent.super.save()
            }
        }
        class Publication implements  Entity{
            String title
        }
    
        class Book extends  Publication{
            String isbn
        }
    
        static void main(String[] args) {
            Entity gina = new Book(id:1,version: 1,title: 'gina', isbn: "11111")
            gina.save()
            assert gina.version == 2
        }
    }
    

4、GroovyBeans使用

4.1、宣告bean

  • /**
     * groovy bean 定義
     * @author liangchen* @date 2020/11/10
     */
    class MyBeanDeom {
    
        static class MyBean implements Serializable{
            String myprop
    				//沒有定義型別
            def untyped
          	//定義型別
            String typed
    				
            def item1, item2
    				//賦值初始值
            def assigned = 'default value'
        }
    
        static void main(String[] args) {
          MyBean myBean =  new MyBean()
           assert 'default value' == myBean.getAssigned()
            myBean.setUntyped('some value')
            assert 'some value' == myBean.getUntyped()
            
        }
    }
    
    
    

4.2、beans執行特徵

  • 獲取field(成員變數)和方法

    • /**
       * 呼叫groovy方法
       * @author liangchen* @date 2020/11/10
       */
      class CallGroovyWayDemo {
      
         static class MrBean {
              String firstname, lastname
              String getName (){
                  return "$firstname $lastname"
              }
          }
      
           static void main(String[] args) {
               def bean = new MrBean(firstname: 'Rowan')
               bean.lastname = 'Jack'
               // 自動呼叫name --> getName 方法
               assert 'Rowan Jack' == bean.name
      
               //獲取成員變數,使用.@
               def beanss = new DoublerBean(value: 100)
               assert 200 == beanss.value
               assert 100 == beanss.@value
      
           }
      
          /**
           * 獲取成員變數,使用.@
           *
           */
      
          static  class DoublerBean {
              public value
      
              void setValue(value) {
                  this.value = value
              }
      
              def getValue() {
                  value * 2
              }
          }
      }
      
      

4.3、在任何類中使用bean 的方法

  • 獲取def 修飾的field 欄位

    • /**
       * 獲取bean的屬性
       * 獲取def 修飾的變數
       * @author liangchen* @date 2020/11/10
       */
      class GDKBeanProperties {
      
          static class ClassWithProperties{
              def someProperty
              public someField
              private somePrivateField
          }
      
          static void main(String[] args) {
             def obj = new ClassWithProperties()
              def store = []
              obj.properties.each { property ->
                  store += property.key
                  store += property.value
              }
              assert store.contains('someProperty')
              assert store.contains('someField')  == false
              assert store.contains('somePrivateField') == false
              assert store.contains('class')
      
              assert obj.properties.size() == 2
          }
      
      }
      
      

4.4、Field、accessors、maps and Expando

  • Expando

    • /**
       * 動態擴充套件屬性和方法 Expando
       * @author liangchen* @date 2020/11/10
       */
      class ExpandoDemo {
      
          static void main(String[] args) {
              def boxer = new Expando()
              assert null == boxer.takeThis
              // 賦值 takeThis 不存在的值
              boxer.takeThis = 'jack'
              assert 'jack' == boxer.takeThis
              // 定義方法
              boxer.fightBack = {times -> delegate.takeThis * times}
              assert  'jackjack' == boxer.fightBack(2)
          }
      }
      
      

5、使用高階語法特性

5.1、使用GPaths查詢物件

  • /**
     *  GPath 解析
     * @author liangchen* @date 2020/11/10
     */
    class GPathInvoiceDemo {
    
        static class Invoice{
            List items
            Date date
        }
    
        static class LineItem{
            Product product
            int count
            int total(){
                return product.dollar * count
            }
        }
    
        static class Product {
            String name
            def dollar
        }
    
        static void main(String[] args) {
            def ulcDate = Date.parse('yyyy-MM-dd', '2015-01-01')
            def otherDate = Date.parse('yyy-MM-dd', '2015-02-02')
            def ulc = new Product(dollar: 1499, name: 'ULC')
            def ve = new Product(dollar: 499, name: 'Visual Editor')
    
            def invoices = [
                    new Invoice(date: ulcDate, items: [
                            new LineItem(count: 5, product: ulc),
                            new LineItem(count: 1, product: ve)
                    ]),
                    new Invoice(date: otherDate, items: [
                            new LineItem(count: 4, product: ve)
                    ])
            ]
            // lineItem 平鋪,拆開
            def allItems = invoices.items.flatten()
    
            // 迴圈呼叫 total方法
            assert [5*1499, 499, 4*499] == allItems*.total()
    
            // 查詢 數量大於 7000的
            assert ['ULC'] == allItems.grep{it.total() > 7000}.product.name
    
            // product == ulc , date日期變成字串
            def searchDates = invoices.grep { it.items.any{it.product == ulc}}.date*.toString()
            assert [ulcDate.toString()] == searchDates
        }
    }
    
    

5.2、注入*操作

  • /**
     *    * 號操作
     * @author liangchen* @date 2020/11/10
     */
    class SpreadDemo {
    
        def getList(){
            return [1,2,3]
        }
    
        def sum(a, b, c) {
            return a + b + c
        }
    
        static void main(String[] args) {
           def spread =  new SpreadDemo()
            // 直接呼叫getList 方法獲取到值作為sum的引數
            assert 6 == spread.sum(*spread.list)
    
            // 直接使用*變數陣列
            def range = (1..3)
            assert [0,1,2,3] == [0, *range]
    
            // 或者map 或者map *:map
            def map = [a:1, b:2]
            assert [a:1, b:2, c:3] == [c:3, *:map]
        }
    
    }
    
    

5.3、利用命令鏈來使用精確語法

6、總結

  1. 方法、成員變數、區域性變數定義(對比java來說的)
  2. groovybean定義

相關文章