01_strage_pattern_策略模式

背景

  1. 你需要中途接手开发一个模拟鸭子的游戏,游戏中有各种鸭子,它们有着不同的外貌,会游泳swim,会叫quack,后面可能会添加其他行为,比如飞行fly。
  2. 你的上一任开发已经离职,他对此系统采用了标准的OO技术,设计了一个鸭子超类,并让各种鸭子继承此超类。

问题

  1. 代码重复问题。各种鸭子叫的方式不尽相同,如果每种鸭子都实现一份swim方法的话会出现大量重复代码。
  2. 扩展性问题。如果给父类添加fly方法则子类都具备该功能,但不是所有鸭子都能飞,比如橡皮鸭。如果让子类实现自己的fly方法又会出现上面的问题。

解决方案

行为的实现不应该跟鸭子类型耦合。因为不同的鸭子对应的行为可能相同,可能不同,如果完全相同,则这些行为可以放在父类中,比如swim,如果完全不同,倒是可以放在子类实现。既然不满足这两点,行为就应当拆出来,做成可以灵活更改的变量。

UML类图

design

代码

package main

import "fmt"

// 鸭子基类
type Duck struct {
	flyBehavior   FlyBehavior
	quackBehavior QuackBehavior
}

func (d *Duck) Swim() {
	fmt.Println("I'm swimming")
}

func (d *Duck) Display() {
	fmt.Println("I'm Displaying")
}

func (d *Duck) SetFly(flyBehavior FlyBehavior) {
	d.flyBehavior = flyBehavior
}

func (d *Duck) SetQuack(quackBehavior QuackBehavior) {
	d.quackBehavior = quackBehavior
}

func (d *Duck) PeformFly() {
	if d.flyBehavior != nil {
		d.flyBehavior.Fly()
	}
}

func (d *Duck) PeformQuack() {
	if d.quackBehavior != nil {
		d.quackBehavior.Quack()
	}
}

// 飞行接口
type FlyBehavior interface {
	Fly()
}

// 飞行算子
type FlyWithWings struct{}

func (f *FlyWithWings) Fly() {
	fmt.Println("I'm flying with wings.")
}

// 飞行算子
type FlyNoWay struct{}

func (f *FlyNoWay) Fly() {
	fmt.Println("I can not fly.")
}

// 呱呱叫接口
type QuackBehavior interface {
	Quack()
}

// 呱呱叫算子
type Quack struct{}

func (f *Quack) Quack() {
	fmt.Println("I'm Quacking.")
}

// 呱呱叫算子
type Squeak struct{}

func (f *Squeak) Quack() {
	fmt.Println("I'm Squeaking.")
}

// 呱呱叫算子
type QuackNoWay struct{}

func (f *QuackNoWay) Quack() {
	fmt.Println("I can not Quack.")
}

// 工厂方法
func NewMallardDuck() *Duck {
	return &Duck{
		flyBehavior:   &FlyWithWings{},
		quackBehavior: &Squeak{},
	}
}

func NewModelDuck() *Duck {
	return &Duck{
		flyBehavior:   &FlyNoWay{},
		quackBehavior: &QuackNoWay{},
	}
}

func main() {
	var mallard *Duck = NewMallardDuck()
	mallard.PeformFly()
	mallard.PeformQuack()
	mallard.SetFly(&FlyNoWay{})
	mallard.PeformFly()

	model := NewModelDuck()
	model.Display()
	mallard.PeformFly()
	mallard.PeformQuack()
	mallard.SetFly(&FlyWithWings{})
	mallard.PeformFly()
}

定义

strage pattern, 策略模式: 定义了一组算法,使其可以互相替换,将行为与类型解耦。

扩展

相比于继承,组合能带来更灵活的复用能力,可在运行时动态地改变行为,has-a关系要优于is-a关系。

原则

  • 针对接口编程,不针对实现编程
  • 多用组合,少用继承
Android 开发中,当出现 "storage/emulated/permission denied" 错误时,表示应用无法访问存储设备的特定路径。这可能是因为应用没有正确的存储访问权限或路径不存在。 首先,我们需要检查应用的权限设置。在 AndroidManifest.xml 文件中,确认是否已添加了相应的存储权限声明。例如,这个错误通常和 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 权限相关。确保在权限声明中正确添加了这些权限。 其次,如果应用的权限已经配置正确,但仍然出现该错误,可能是由于路径不存在。请确保指定的路径在设备上存在,并且可以通过代码访问。通常,路径 "storage/emulated/" 是指向设备的内部存储的根目录。然而,具体路径可能因制造商和设备而异,因此在使用之前最好使用代码来获取正确的路径。可以使用 Environment.getExternalStorageDirectory() 方法获取内部存储的准确路径。 最后,还可能是由于设备的文件系统权限设置导致该错误。在某些情况下,操作系统可能阻止应用访问某些特定的文件或文件夹。这种情况下,较低的权限可能需要在应用程序中进行处理才能访问这些文件。 总结:要解决 "storage/emulated/permission denied" 错误,我们需要确保应用具有正确的存储权限声明、路径存在和正确的路径访问方法、以及设备文件系统的相关权限设置。通过仔细检查这些因素,可以解决该错误并顺利访问所需的路径和文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值