工厂模式
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
- 主要解决:主要解决接口选择的问题。
- 何时使用:我们明确地计划不同条件下创建不同实例时。
- 使用场景:
- 日志记录器
- 数据库访问
- 设计一个连接服务器的框架
一个函数可以自行选择用什么类来实现一个或一套方法
package Factory
import (
"fmt"
"testing"
)
type Restaurant interface {
GetFood()
}
type Donglaishun struct {}
func (d *Donglaishun) GetFood() {
fmt.Println("东来顺")
}
type Qingfeng struct {}
func (q *Qingfeng) GetFood() {
fmt.Println("庆丰")
}
func NewRestaurant(name string) Restaurant{
switch name {
case "d":
return &Donglaishun{}
case "q":
return &Qingfeng{}
}
return nil
}
func TestNewRestaurant(t *testing.T) {
NewRestaurant(d).GetFood()
NewRestaurant(d).GetFood()
}
抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 主要解决:主要结局接口选择的问题
- 何时使用:系统的产品有多于一个的产品族,而系统只消费其中的某一族产品
- 使用场景:
- qq换皮肤,一整套一起换
- 生成不同操作系统的程序
一个类通过不同的方法返回不同的类
package Abstract_Factory
import (
"fmt"
"testing"
)
type Lunch interface{
Cook()
}
type Rise struct {}
func (r *Rise) Cook() {
fmt.Println("rice")
}
type Tomato struct {}
func (t *Tomato) Cook() {
fmt.Println("tomato")
}
type LunchFactory interface {
CreateFood() Lunch
CreateVegetable() Lunch
}
type SimpleLunchFactory struct {}
func NewSimpleLunchFactory() LunchFactory{
return &SimpleLunchFactory{}
}
func (s *SimpleLunchFactory) CreateFood() Lunch {
return &Rise{}
}
func (s *SimpleLunchFactory) CreateVegetable() Lunch {
return &Tomato{}
}
func TestNewSimpleLunchFactory(t *testing.T) {
factory := NewSimpleLunchFactory()
food := factory.CreateFood()
food.Cook()
vegetable := factory.CreateVegetable()
vegetable.Cook()
}
外观模式
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。
- 何时使用:
- 客户端不需要知道系统内部的复杂联系,整个系统只需提供一个”接待员”即可。
- 定义系统的入口。
- 使用场景:
- 为复杂的模块或子系统提供外界访问的模块
- 子系统相对独立
- 预防低水平人员带来的风险
通过返回一个简单的接口而实现了复杂的操作
package Facade
import (
"fmt"
"testing"
)
type CarModel struct {}
func NewCarModel() *CarModel {
return &CarModel{}
}
func (c *CarModel) SetModel() {
fmt.Fprintf(outputWriter, " CarModel - SetModel\n")
}
type CarEngine struct {}
func NewCarEngine() *CarEngine {
return &CarEngine{}
}
func (c *CarEngine) SetEngine() {
fmt.Fprintf(outputWriter, " CarEngine - SetEngine\n")
}
type CarBody struct {}
func NewCarBody() *CarBody {
return &CarBody{}
}
func (c *CarBody) SetBody() {
fmt.Fprintf(outputWriter, " CarBody - SetBody\n")
}
type CarAccessories struct {}
func NewCarAccessories() *CarAccessories {
return &CarAccessories{}
}
func (c *CarAccessories) SetAccessories() {
fmt.Fprintf(outputWriter, " CarAccessories - SetAccessories\n")
}
type CarFacade struct {
accessories *CarAccessories
body *CarBody
engine *CarEngine
model *CarModel
}
func NewCarFacade() *CarFacade {
return &CarFacade{
accessories: NewCarAccessories(),
body: NewCarBody(),
engine: NewCarEngine(),
model: NewCarModel(),
}
}
func (c *CarFacade) CreateCompleteCar() {
fmt.Fprintf(outputWriter, "******** Creating a Car **********\n")
c.model.SetModel()
c.engine.SetEngine()
c.body.SetBody()
c.accessories.SetAccessories()
fmt.Fprintf(outputWriter, "******** Car creation is completed. **********\n")
}
func TestCarFacade_CreateCompleteCar(t *testing.T) {
facade := NewCarFacade()
facade.CreateCompleteCar()
}
建造者模式
将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
- 主要解决:主要解决在软件系统中,有时候面临着”一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
- 何时使用:一些基本部件不会变,而其组合经常变化的时候
- 场景:
- 套餐,东西不变,但组合一直变
一些基本部件不会变,而组合经常变化
- 套餐,东西不变,但组合一直变
package Builder
import (
"fmt"
"testing"
)
type Builder interface {
Build()
}
type Director struct {
builder Builder
}
func NewDirector(b Builder) Director {
return Director{builder: b}
}
func (d *Director) Construct() {
d.builder.Build()
}
type ConcreteBuilder struct {
built bool
}
func NewConcreteBuilder() ConcreteBuilder {
return ConcreteBuilder{false}
}
func (b *ConcreteBuilder) Build() {
b.built = true
}
type Product struct {
Built bool
}
func (b *ConcreteBuilder) GetResult() Product {
return Product{b.built}
}
func TestConcreteBuilder_GetResult(t *testing.T) {
builder := NewConcreteBuilder()
director := NewDirector(&builder)
director.Construct()
product := builder.GetResult()
fmt.Println(product.Built)
}
桥接模式
将抽象部分与实现部分分离,使它们都可以独立的变化。
- 主要解决:在有很多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不方便
- 何时使用:实现系统可能有多个角度分类,每一种角度都可能变化
- 场景:
- 系统需要在构建的抽象化角色于具体化角色之间增加更多灵活性(模型-实例)
- 不希望使用继承或因为多层次导致系统类的个数急剧增加的系统
- 一个类存在两个独立变化的维度,且两个维度都需要扩展
具体的描述某些维度
package Bridage
import (
"fmt"
"time"
"testing"
)
type Draw interface {
DrawCircle(radius, x, y int)
}
type RedCircle struct {}
func (g *RedCircle) DrawCircle(radius, x, y int) {
fmt.Println("radius、x、y:", radius, x, y)
}
type YellowCircle struct {}
func (g *YellowCircle) DrawCircle(radius, x, y int) {
fmt.Println("radius、x、y:", radius, x, y)
}
type Shape struct {
draw Draw
}
func (s *Shape) Shape(d Draw) {
s.draw = d
time.Now().Unix()
}
type Circle struct {
shape Shape
x int
y int
radius int
}
func (c *Circle) Constructor(x int, y int, radius int, draw Draw) {
c.x = x
c.y = y
c.radius = radius
c.shape.Shape(draw)
}
func (c *Circle) Cook() {
c.shape.draw.DrawCircle(c.radius, c.x, c.y)
}
func TestCircle_Draw(t *testing.T) {
redCircle := Circle{}
redCircle.Constructor(100, 100, 10, &RedCircle{})
yellowCircle := Circle{}
yellowCircle.Constructor(200, 200, 20, &YellowCircle{})
redCircle.Cook()
yellowCircle.Cook()
}
命令模式
将一个请求封装成一个对象,从而可以用不同的请求对客户进行参数化。
- 主要解决:某些场合下,紧耦合的设计无法满足行为
- 何时使用:在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
- 使用场景:
- GUI的每一个按钮
- 模拟CMD
使用一个函数可以灵活的使用其方法
package Command
import (
"fmt"
"testing"
)
type Person struct {
name string
cmd Command
}
type Command struct {
person *Person
method func()
}
func NewCommand(p *Person, method func()) Command {
return Command{
person: p,
method: method,
}
}
func (c *Command) Execute() {
c.method()
}
func NewPerson(name string, cmd Command) Person {
return Person{
name: name,
cmd: cmd,
}
}
func (p *Person) Buy() {
fmt.Println(fmt.Sprintf("%s is buying ", p.name))
p.cmd.Execute()
}
func (p *Person) Cook() {
fmt.Println(fmt.Sprintf("%s is cooking ", p.name))
p.cmd.Execute()
}
func (p *Person) Wash() {
fmt.Println(fmt.Sprintf("%s is washing ", p.name))
p.cmd.Execute()
}
func (p *Person) Listen() {
fmt.Println(fmt.Sprintf("%s is Listening ", p.name))
}
func (p *Person) Talk() {
fmt.Println(fmt.Sprintf("%s is Talking ", p.name))
p.cmd.Execute()
}
func TestCommand_Execute(t *testing.T) {
laowang := NewPerson("wang", NewCommand(nil, nil))
laozhang := NewPerson("zhang", NewCommand(&laowang, laowang.Listen))
laofeng := NewPerson("feng", NewCommand(&laozhang, laozhang.Buy))
laoding := NewPerson("ding", NewCommand(&laofeng, loafeng.Cook))
laoli := NewPerson("li", NewCommand(&laoding, laoding.Wash))
laoli.Talk()
}