美文网首页
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