Go实现设计模式--策略模式

Go语言中的方法和接口

go语言中有方法接口

方法

在函数的func和函数名间增加一个特殊的接收器类型,接收器可以是结构体类型或非结构体类型。接收器可以在方法内部访问。创建一个接收器类型为Type的methodName方法。

func (t Type) methodName(parameter list) {
}

接口

接口是方法(方法签名,method signature)的集合。当一个类型定义了接口中的所有方法,就称它实现了该接口。与OOP类似,接口定义了一个类型应该具有的方法,由该类型决定如何实现这些方法。

type myInterface interface{
    method1()
    method2()
}

例子

存在名为Animal的interface,其内有方法makeSound()
存在Dog,Cat的结构体,实现了makeSound()方法,即实现了接口Animal中的所有方法
则Dog,Cat就可以视作是Animal来使用,实现多态,也就是接口的不同实现方式

package main

import "fmt"

type Animal interface {
	makeSound()
}

type Dog struct {
}

func (t Dog) makeSound() {
	t.bark()
}

func (t Dog) bark(){
	fmt.Println("wang wang")
}

type Cat struct {
}

func (t Cat) makeSound() {
	t.meom()
}

func (t Cat) meom(){
	fmt.Println("miao miao")
}


func sound(a Animal){
	a.makeSound()
}

func main() {
	dog := new(Dog)
	cat := new(Cat)
	sound(dog)
	sound(cat)
}

输出:

wang wang
miao miao

策略模式

定义

定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法变化独立于使用算法的用户。

介绍

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。

何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。

如何解决:将这些算法封装成一个一个的类,任意地替换。

关键代码:实现同一个接口。

应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。

优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

使用场景
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2、一个系统需要动态地在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

代码示例

1.定义duck类,是所有鸭子的集合,其内含有FlyBehavior,QuackBehavior 分别是所有飞行行为的集合及鸭子叫行为的集合

type FlyBehavior interface {
	fly()
}

type QuackBehavior interface {
	quack()
}

//策略类:
//设计一个鸭子类,同时有飞行行为,叫行为
//拥有两个接口:performQuack,performFly
type Duck struct {
	flyBehavior FlyBehavior
	quackBehavior QuackBehavior
}

2.有了以上结构体,定义鸭子叫,就是使用实现了QuackBehavior对象的quack()方法具体实现参考performQuack,飞行行为类似,将行为与鸭子剥离开

func (d Duck) performQuack() {
	d.quackBehavior.quack()
}

func (d Duck) performFly() {
	d.flyBehavior.fly()
}

3.因为duck类内有两个Behavior,所以要对其进行初始化,分别以具体的实现了两个Behavior的对象初始化对duck赋值才能使用其内的两个behavior,具体实现参考NewDuck

func NewDuck(fb FlyBehavior,qb QuackBehavior) *Duck{
	return &Duck{
		flyBehavior:fb,
		quackBehavior:qb,
	}
}

4.因为goloang没有继承,所以要使用duck可以通过struct间使用匿名引入的方式实现对象属性方法的组合

type MallardDuck struct{
	*Duck
}

5.可以动态的改变子结构体内的方法

func (d MallardDuck) setQuack(behavior QuackBehavior) {
	d.quackBehavior = behavior
}

整体可运行代码如下

package main

import "fmt"

type FlyBehavior interface {
	fly()
}

type QuackBehavior interface {
	quack()
}

//策略类:
//设计一个鸭子类,同时有飞行行为,叫行为
//拥有两个接口:performQuack,performFly
type Duck struct {
	flyBehavior FlyBehavior
	quackBehavior QuackBehavior
}
//策略类操作方法
func (d Duck) performQuack() {
	d.quackBehavior.quack()
}

func (d Duck) performFly() {
	d.flyBehavior.fly()
}
/*策略类构造函数*/
func NewDuck(fb FlyBehavior,qb QuackBehavior) *Duck{
	return &Duck{
		flyBehavior:fb,
		quackBehavior:qb,
	}
}

type FlyWithWings struct{
}

func (d FlyWithWings) fly() {
	fmt.Println("I can fly by wings.")
}

type QuackOne struct{
}

func (d QuackOne) quack() {
	fmt.Println("I can Quack.")
}

type QuackTwo struct{
}

func (d QuackTwo) quack() {
	fmt.Println("I can not quack.")
}

//因为结构体没有继承所以可以用匿名字段来实现继承
//但是不能以此结构体作为父类使用
type MallardDuck struct{
	*Duck
}

func (d MallardDuck) display() {
	fmt.Println("MallardDuck")
}

func (d MallardDuck) setQuack(behavior QuackBehavior) {
	d.quackBehavior = behavior
}

func perform(d Duck){
	d.quackBehavior.quack()
	d.flyBehavior.fly()
}

func main() {
    f1 :=  new(FlyWithWings)
    q1:=new(QuackOne)
    q2:=new(QuackTwo)

    var md1 MallardDuck

    md1.Duck = NewDuck(f1,q1)
	perform(*md1.Duck)
    md1.display()
    md1.setQuack(q2)
    md1.performQuack()
}

运行结果

I can Quack.
I can fly by wings.
MallardDuck
I can not quack.

参考文章:
https://www.runoob.com/design-pattern/strategy-pattern.html

发布了222 篇原创文章 · 获赞 35 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/hello_bravo_/article/details/104786592
今日推荐