美文网首页
Design patterns in Groovy

Design patterns in Groovy

作者: 坚持到底v2 | 来源:发表于2018-03-27 14:39 被阅读0次

    文档

    http://www.groovy-lang.org/design-patterns.html


    1、 Patterns

    1.1. Abstract Factory Pattern

    抽象工厂模式

    1.1.1. Example

    假设我们要写一个 游戏系统。
    我们也许注意到很多游戏都有类似的features和control
    我们决定尝试分离 通用的 和 game-specific 代码到不同的类中

    首先,我们看一下 Two-up game 的 game-specific 代码

    class TwoupMessages {
        def welcome = 'Welcome to the twoup game, you start with $1000'
        def done = 'Sorry, you have no money left, goodbye'
    }
    
    class TwoupInputConverter {
        def convert(input) { input.toInteger() }
    }
    
    class TwoupControl {
        private money = 1000
        private random = new Random()
        private tossWasHead() {
            def next = random.nextInt()
            return next % 2 == 0
        }
        def moreTurns() {
            if (money > 0) {
                println "You have $money, how much would you like to bet?"
                return true
            }
    
            false
        }
        def play(amount) {
            def coin1 = tossWasHead()
            def coin2 = tossWasHead()
            if (coin1 && coin2) {
                money += amount
                println 'You win'
            } else if (!coin1 && !coin2) {
                money -= amount
                println 'You lose'
            } else {
                println 'Draw'
            }
        }
    }
    

    然后是 一个 number guessing game 的 game-specific 代码

    class GuessGameMessages {
        def welcome = 'Welcome to the guessing game, my secret number is between 1 and 100'
        def done = 'Correct'
    }
    
    class GuessGameInputConverter {
        def convert(input) { input.toInteger() }
    }
    
    class GuessGameControl {
        private lower = 1
        private upper = 100
        private guess = new Random().nextInt(upper - lower) + lower
        def moreTurns() {
            def done = (lower == guess || upper == guess)
            if (!done) {
                println "Enter a number between $lower and $upper"
            }
    
            !done
        }
        def play(nextGuess) {
            if (nextGuess <= guess) {
                lower = [lower, nextGuess].max()
            }
            if (nextGuess >= guess) {
                upper = [upper, nextGuess].min()
            }
        }
    }
    

    现在,让我们写工厂代码:

    def guessFactory = [messages: GuessGameMessages, control: GuessGameControl, converter: GuessGameInputConverter]
    def twoupFactory = [messages: TwoupMessages, control: TwoupControl, converter: TwoupInputConverter]
    
    class GameFactory {
        def static factory
        def static getMessages() { return factory.messages.newInstance() }
        def static getControl() { return factory.control.newInstance() }
        def static getConverter() { return factory.converter.newInstance() }
    }
    

    接下来是我们如何使用这个工厂

    GameFactory.factory = twoupFactory
    def messages = GameFactory.messages
    def control = GameFactory.control
    def converter = GameFactory.converter
    println messages.welcome
    def reader = new BufferedReader(new InputStreamReader(System.in))
    while (control.moreTurns()) {
        def input = reader.readLine().trim()
        control.play(converter.convert(input))
    }
    println messages.done
    
    

    1.2. Adapter Pattern

    适配器模式,有时也被称为 wrapper模式

    1.2.1. Delegation Example

    假设我们有下面的类

    class SquarePeg {
        def width
    }
    
    class RoundPeg {
        def radius
    }
    
    class RoundHole {
        def radius
        def pegFits(peg) {
            peg.radius <= radius
        }
        String toString() { "RoundHole with radius $radius" }
    }
    
    

    我们可以使用 hole.pegFits(new RoundPeg(radius:4))
    但是不能使用 SquarePeg,因为 SquarePeg 没有 radius property

    所以我们可以创建一个 Adapter

    class SquarePegAdapter {
        def peg
        def getRadius() {
            Math.sqrt(((peg.width / 2) ** 2) * 2)
        }
        String toString() {
            "SquarePegAdapter with peg width $peg.width (and notional radius $radius)"
        }
    }
    

    现在我们可以使用 hole.pegFits(new SquarePegAdapter(peg: new SquarePeg(width: 4)))

    1.2.2. Inheritance Example

    接上面的示例,我们也可以使用继承的方式实现Adapter

    class SquarePegAdapter extends SquarePeg {
        def getRadius() {
            Math.sqrt(((width / 2) ** 2) * 2)
        }
        String toString() {
            "SquarePegAdapter with width $width (and notional radius $radius)"
        }
    }
    
    

    现在我们可以使用 hole.pegFits(new SquarePegAdapter(width: 4))

    1.2.3. Adapting using Closures

    接上面的示例,我们也可以Closure的方式实现Adapter

    先定义一个接口

    interface RoundThing {
        def getRadius()
    }
    

    然后定义一个Closure

    def adapter = {
        p -> [getRadius: { Math.sqrt(((p.width / 2) ** 2) * 2) }] as RoundThing
    }
    

    现在我们可以使用 hole.pegFits(adapter(new SquarePeg(width: 4)))

    1.2.4. Adapting using the ExpandoMetaClass

    接上面的示例,我们也可以 ExpandoMetaClass 的方式实现Adapter

    def peg = new SquarePeg(width: 4)
    peg.metaClass.radius = Math.sqrt(((peg.width / 2) ** 2) * 2)
    

    现在我们可以使用 hole.pegFits(new SquarePeg(width: 4))

    1.3. Bouncer Pattern

    Bouncer模式描述了一种方法的使用,其唯一目的是要么抛出异常(当特定条件成立时)或者什么都不做。
    这种方法通常用于 defensively guard pre-conditions of a method.

    编写实用程序方法时,应始终防范错误的输入参数。
    在编写内部方法时,您可以通过进行足够的单元测试来确保始终保持某些前提条件。
    在这种情况下,您可能会降低对您的方法进行防范的可能性。

    在Groovy中你可以频繁的使用 assert 而不是使用大量的checker方法

    1.3.1. Null Checking Example

    void doStuff(String name, Object value) {
        assert name != null, 'name should not be null'
        assert value != null, 'value should not be null'
        // do stuff
    }
    

    1.3.2. Validation Example

    def stringDivide(String dividendStr, String divisorStr) {
        assert dividendStr =~ NumberChecker.NUMBER_PATTERN
        assert divisorStr =~ NumberChecker.NUMBER_PATTERN
        def dividend = dividendStr.toDouble()
        def divisor = divisorStr.toDouble()
        assert divisor != 0, 'Divisor must not be 0'
        dividend / divisor
    }
    
    

    1.4. Chain of Responsibility Pattern

    责任链模式

    1.4.1. Example

    class UnixLister {
        private nextInLine
        UnixLister(next) { nextInLine = next }
        def listFiles(dir) {
            if (System.getProperty('os.name') == 'Linux') {
                println "ls $dir".execute().text
            } else {
                nextInLine.listFiles(dir)
            }
        }
    }
    
    class WindowsLister {
        private nextInLine
        WindowsLister(next) { nextInLine = next }
        def listFiles(dir) {
            if (System.getProperty('os.name') == 'Windows XP') {
                println "cmd.exe /c dir $dir".execute().text
            } else {
                nextInLine.listFiles(dir)
            }
        }
    }
    
    class DefaultLister {
        def listFiles(dir) {
            new File(dir).eachFile { f -> println f }
        }
    }
    
    def lister = new UnixLister(new WindowsLister(new DefaultLister()))
    
    lister.listFiles('Downloads')
    
    

    1.5. Composite Pattern

    1.5.1. Example

    1.6. Decorator Pattern

    1.7. Delegation Pattern

    1.8. Flyweight Pattern

    1.9. Iterator Pattern

    1.10. Loan my Resource Pattern

    1.11. Null Object Pattern

    1.12. Pimp my Library Pattern

    1.13. Proxy Pattern

    1.14. Singleton Pattern

    1.15. State Pattern

    1.16. Strategy Pattern

    1.17. Template Method Pattern

    1.18. Visitor Pattern

    相关文章

      网友评论

          本文标题:Design patterns in Groovy

          本文链接:https://www.haomeiwen.com/subject/urfscftx.html