在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。
动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码 & 减少子类个数)。
例如,有一个流操作,我们抽出它的通用方法,然后在继承并实现这些方法,
package decorate
import "fmt"
type Stream interface {
Read(nums int) byte
Seek(position int)
Write(data byte)
}
// 文件流
type FileStream struct {
Stream
}
func (fs *FileStream) Read(nums int) byte {
fmt.Println("File stream read")
return 0
}
func (fs *FileStream) Seek(position int) {
fmt.Println("File stream seek")
}
func (fs *FileStream) Write(data byte) {
fmt.Println("File stream write")
}
// 网络流
type NetworkStream struct {
Stream
}
// 具体实现
func (ns *NetworkStream) Read(nums int) byte {
fmt.Println("Network stream read")
return 0
}
func (ns *NetworkStream) Seek(position int) {
fmt.Println("Network stream seek")
}
func (ns *NetworkStream) Write(data byte) {
fmt.Println("Network stream write")
}
// 内存流
type MemoryStream struct {
Stream
}
// 具体实现
func (ms *MemoryStream) Read(nums int) byte {
fmt.Println("Memory stream read")
return 0
}
func (ms *MemoryStream) Seek(position int) {
fmt.Println("Memory stream seek")
}
func (ms *MemoryStream) Write(data byte) {
fmt.Println("Memory stream write")
}
然后我们需要对流进行加密操作,但是加密操作需要对于具体的某个流进行操作,于是有以下代码
// 扩展操作,对文件流加密
type CryptoFileStream struct {
fs *FileStream
}
// 具体实现
func (cfs *CryptoFileStream) Read(nums int) byte {
//额外操作
fmt.Println("Encryption Before Read ")
res := cfs.fs.Read(nums)
//额外操作
fmt.Println("Encryption After Read ", res)
return res
}
func (cfs *CryptoFileStream) Seek(position int) {
fmt.Println("Encryption Before Seek")
cfs.fs.Seek(position)
fmt.Println("Encryption After Seek")
}
func (cfs *CryptoFileStream) Write(data byte) {
fmt.Println("Encryption Before Write")
cfs.fs.Write(data)
fmt.Println("Encryption After Write")
}
然后我们发现,不管对什么流操作,但加密流的方法处理流程是不变的。可能还需要,Buffer
扩展。代码重复度过高。每次都继承,可以看到有这么多类
可见这类的增长深度是有多块,1+n+n*m!/2
。对于变化部分的封装,文件、网络、内存流实现不变,对于扩展功能封装.
package decorate
import "fmt"
type Stream interface {
Read(nums int) byte
Seek(position int)
Write(data byte)
}
// 文件流
type FileStream struct {
Stream
}
func (fs *FileStream) Read(nums int) byte {
fmt.Println("File stream read")
return 0
}
func (fs *FileStream) Seek(position int) {
fmt.Println("File stream seek")
}
func (fs *FileStream) Write(data byte) {
fmt.Println("File stream write")
}
// 网络流
type NetworkStream struct {
Stream
}
// 具体实现
func (ns *NetworkStream) Read(nums int) byte {
fmt.Println("Network stream read")
return 0
}
func (ns *NetworkStream) Seek(position int) {
fmt.Println("Network stream seek")
}
func (ns *NetworkStream) Write(data byte) {
fmt.Println("Network stream write")
}
// 内存流
type MemoryStream struct {
Stream
}
// 具体实现
func (ms *MemoryStream) Read(nums int) byte {
fmt.Println("Memory stream read")
return 0
}
func (ms *MemoryStream) Seek(position int) {
fmt.Println("Memory stream seek")
}
func (ms *MemoryStream) Write(data byte) {
fmt.Println("Memory stream write")
}
// 扩展操作,对流加密
type CryptoStream struct {
Stream //继承,相当于必须实现Stream接口
stream Stream //流指针,运行时确定
}
// 构造器
func NewCryptoStream(stream Stream) *CryptoStream {
return &CryptoStream{stream: stream}
}
// 具体实现
func (cs *CryptoStream) Read(nums int) byte {
fmt.Println("Crypto stream before read")
cs.stream.Read(nums)
fmt.Println("Crypto stream after read")
return 0
}
func (cs *CryptoStream) Seek(position int) {
fmt.Println("Crypto stream before seek")
cs.stream.Seek(position)
fmt.Println("Crypto stream after seek")
}
func (cs *CryptoStream) Write(data byte) {
fmt.Println("Crypto stream before write")
cs.stream.Write(data)
fmt.Println("Crypto stream after write")
}
// 扩展操作,buffered
type BufferedStream struct {
Stream //继承,相当于必须实现Stream接口
stream Stream //流指针,运行时确定
}
// 构造器
func NewBufferedStream(stream Stream) *BufferedStream {
return &BufferedStream{stream: stream}
}
func (bs *BufferedStream) Read(nums int) byte {
fmt.Println("Buffered stream before read")
bs.stream.Read(nums)
fmt.Println("Buffered stream after read")
return 0
}
func (bs *BufferedStream) Seek(position int) {
fmt.Println("Buffered stream before seek")
bs.stream.Seek(position)
fmt.Println("Buffered stream after seek")
}
func (bs *BufferedStream) Write(data byte) {
fmt.Println("Buffered stream before write")
bs.stream.Write(data)
fmt.Println("Buffered stream after write")
}
// 扩展操作,CryptBuffered
type CryptBufferedStream struct {
Stream //继承,相当于必须实现Stream接口
stream Stream //流指针,运行时确定
}
// 构造器
func NewCryptBufferedStream(stream Stream) *CryptBufferedStream {
return &CryptBufferedStream{stream: stream}
}
// 具体实现
func (cbs *CryptBufferedStream) Read(nums int) byte {
fmt.Println("CryptBuffered stream before read")
cbs.stream.Read(nums)
fmt.Println("CryptBuffered stream after read")
return 0
}
func (cbs *CryptBufferedStream) Seek(position int) {
fmt.Println("CryptBuffered stream before seek")
cbs.stream.Seek(position)
fmt.Println("CryptBuffered stream after seek")
}
func (cbs *CryptBufferedStream) Write(data byte) {
fmt.Println("CryptBuffered stream before write")
cbs.stream.Write(data)
fmt.Println("CryptBuffered stream after write")
}
图不一定标准,具体使用,可以通过组合实现想要的功能
func TestCryptoBufferedFileStream_Read(t *testing.T) {
fs := &FileStream{}
cryptoStream := NewCryptoStream(fs)
bufferedStream := NewBufferedStream(cryptoStream)
bufferedStream.Read(10)
}
由于每个具体实现类里都有Stream
字段,所以进一步抽象。提取出Decorate
类,再由具体扩展去继承该类。
package decorate
import "fmt"
type Stream interface {
Read(nums int) byte
Seek(position int)
Write(data byte)
}
// 文件流
type FileStream struct {
Stream
}
func (fs *FileStream) Read(nums int) byte {
fmt.Println("File stream read")
return 0
}
func (fs *FileStream) Seek(position int) {
fmt.Println("File stream seek")
}
func (fs *FileStream) Write(data byte) {
fmt.Println("File stream write")
}
// 网络流
type NetworkStream struct {
Stream
}
// 具体实现
func (ns *NetworkStream) Read(nums int) byte {
fmt.Println("Network stream read")
return 0
}
func (ns *NetworkStream) Seek(position int) {
fmt.Println("Network stream seek")
}
func (ns *NetworkStream) Write(data byte) {
fmt.Println("Network stream write")
}
// 内存流
type MemoryStream struct {
Stream
}
// 具体实现
func (ms *MemoryStream) Read(nums int) byte {
fmt.Println("Memory stream read")
return 0
}
func (ms *MemoryStream) Seek(position int) {
fmt.Println("Memory stream seek")
}
func (ms *MemoryStream) Write(data byte) {
fmt.Println("Memory stream write")
}
// 抽象出Stream的装饰器
type DecorateStream struct {
Stream //继承,必须实现Stream接口,当然可以交给子类实现
}
// 构造器
func NewDecorateStream(stream Stream) DecorateStream {
return DecorateStream{
Stream: stream,
}
}
// 扩展操作,对流加密
type CryptoStream struct {
DecorateStream //继承,
}
// 构造器
func NewCryptoStream(stream Stream) *CryptoStream {
return &CryptoStream{
DecorateStream: NewDecorateStream(stream),
}
}
// 具体实现
func (cs *CryptoStream) Read(nums int) byte {
fmt.Println("Crypto stream before read")
cs.DecorateStream.Read(nums)
fmt.Println("Crypto stream after read")
return 0
}
func (cs *CryptoStream) Seek(position int) {
fmt.Println("Crypto stream before seek")
cs.DecorateStream.Seek(position)
fmt.Println("Crypto stream after seek")
}
func (cs *CryptoStream) Write(data byte) {
fmt.Println("Crypto stream before write")
cs.DecorateStream.Write(data)
fmt.Println("Crypto stream after write")
}
// 扩展操作,buffered
type BufferedStream struct {
DecorateStream //继承,
}
// 构造器
func NewBufferedStream(stream Stream) *BufferedStream {
return &BufferedStream{DecorateStream: NewDecorateStream(stream)}
}
func (bs *BufferedStream) Read(nums int) byte {
fmt.Println("Buffered stream before read")
bs.DecorateStream.Read(nums)
fmt.Println("Buffered stream after read")
return 0
}
func (bs *BufferedStream) Seek(position int) {
fmt.Println("Buffered stream before seek")
bs.DecorateStream.Seek(position)
fmt.Println("Buffered stream after seek")
}
func (bs *BufferedStream) Write(data byte) {
fmt.Println("Buffered stream before write")
bs.DecorateStream.Write(data)
fmt.Println("Buffered stream after write")
}
使用
func TestCryptoBufferedFileStream_Read(t *testing.T) {
fs := &FileStream{}
cryptoStream := NewCryptoStream(fs)
bufferedStream := NewBufferedStream(cryptoStream)
var stream Stream
stream = bufferedStream
stream.Read(10)
}
类图
这样类的个数是1+n+m
.
组合由于继承!
类图,同时想要继承和组合同一个对象,大概率是装饰模式。
将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。
Message
抽象实现
type Messager interface {
Login(username string, password string)
SendMessage(message string)
SendPicture(image image.Image)
PlaySound()
DrawShape()
WriteText()
Connect()
}
对于PC平台
// 平台实现
type PCMessagerBase struct {
Messager
}
func (messager *PCMessagerBase) PlaySound() {
//PC ...
}
func (messager *PCMessagerBase) DrawShape() {
//PC ...
}
func (messager *PCMessagerBase) WriteText() {
//PC ...
}
func (messager *PCMessagerBase) Connect() {
//PC ...
}
对于Mobile平台
type MobileMessagerBase struct {
Messager
}
func (messager *MobileMessagerBase) PlaySound() {
//Mobile ...
}
func (messager *MobileMessagerBase) DrawShape() {
//Mobile ...
}
func (messager *MobileMessagerBase) WriteText() {
//Mobile ...
}
func (messager *MobileMessagerBase) Connect() {
//Mobile ...
}
他们的主要区别在于,
PlaySound()
DrawShape()
WriteText()
Connect()
这些方法的实现上有所区别。
接下来是业务的抽象实现,精简版业务
// 业务抽象
type PCMessagerLite struct {
PCMessagerBase
}
func (pc *PCMessagerLite) Login(username string, password string) {
pc.Connect()
//...
}
func (pc *PCMessagerLite) SendMessage(message string) {
pc.WriteText()
}
func (pc *PCMessagerLite) SendPicture(image image.Image) {
pc.DrawShape()
}
复杂业务
type PCMessagerPerfect struct {
PCMessagerBase
}
func (pc *PCMessagerPerfect) Login(username string, password string) {
pc.PlaySound()
//...
pc.Connect()
//...
}
func (pc *PCMessagerPerfect) SendMessage(message string) {
pc.PlaySound()
//...
pc.WriteText()
//...
}
func (pc *PCMessagerPerfect) SendPicture(image image.Image) {
pc.PlaySound()
//...
pc.DrawShape()
//..
}
对于移动端也有类似的实现。
如果要使用,
var messager Messager
messager = &PCMessagerPerfect{}
类图
这样的话,假设业务抽象有m个,类的数目就有:1+n+m*n
个,n种平台
问题:
解决:
初步抽象,继承转指针
// 业务抽象
type PCMessagerLite struct {
messager *PCMessagerBase
}
func (pc *PCMessagerLite) Login(username string, password string) {
pc.messager.Connect()
//...
}
func (pc *PCMessagerLite) SendMessage(message string) {
pc.messager.WriteText()
}
func (pc *PCMessagerLite) SendPicture(image image.Image) {
pc.messager.DrawShape()
}
type PCMessagerPerfect struct {
messager *PCMessagerBase
}
func (pc *PCMessagerPerfect) Login(username string, password string) {
pc.messager.PlaySound()
//...
pc.messager.Connect()
//...
}
func (pc *PCMessagerPerfect) SendMessage(message string) {
pc.messager.PlaySound()
//...
pc.messager.WriteText()
//...
}
func (pc *PCMessagerPerfect) SendPicture(image image.Image) {
pc.messager.PlaySound()
//...
pc.messager.DrawShape()
//..
}
可用发现这个指针可用进一步抽象,使得其既可以是Mobile
,也可以是PC
package bridge
import "image"
type Messager interface {
Login(username string, password string)
SendMessage(message string)
SendPicture(image image.Image)
PlaySound()
DrawShape()
WriteText()
Connect()
}
// 平台实现
type PCMessagerBase struct {
Messager
}
func (messager *PCMessagerBase) PlaySound() {
//PC ...
}
func (messager *PCMessagerBase) DrawShape() {
//PC ...
}
func (messager *PCMessagerBase) WriteText() {
//PC ...
}
func (messager *PCMessagerBase) Connect() {
//PC ...
}
type MobileMessagerBase struct {
Messager
}
func (messager *MobileMessagerBase) PlaySound() {
//Mobile ...
}
func (messager *MobileMessagerBase) DrawShape() {
//Mobile ...
}
func (messager *MobileMessagerBase) WriteText() {
//Mobile ...
}
func (messager *MobileMessagerBase) Connect() {
//Mobile ...
}
// 业务抽象
type MessagerLite struct {
messager Messager //既可以是PC又可用是Mobile
}
func (lite *MessagerLite) Login(username string, password string) {
lite.messager.Connect()
//...
}
func (lite *MessagerLite) SendMessage(message string) {
lite.messager.WriteText()
}
func (lite *MessagerLite) SendPicture(image image.Image) {
lite.messager.DrawShape()
}
type MessagerPerfect struct {
messager Messager
}
func (perfect *MessagerPerfect) Login(username string, password string) {
perfect.messager.PlaySound()
//...
perfect.messager.Connect()
//...
}
func (perfect *MessagerPerfect) SendMessage(message string) {
perfect.messager.PlaySound()
//...
perfect.messager.WriteText()
//...
}
func (perfect *MessagerPerfect) SendPicture(image image.Image) {
perfect.messager.PlaySound()
//...
perfect.messager.DrawShape()
//..
}
进一步发现,
type Messager interface {
Login(username string, password string)
SendMessage(message string)
SendPicture(image image.Image)
PlaySound()
DrawShape()
WriteText()
Connect()
}
是不合理的,拆分为两个部分
type Messager interface {
Login(username string, password string)
SendMessage(message string)
SendPicture(image image.Image)
}
type MessagerImp interface {
PlaySound()
DrawShape()
WriteText()
Connect()
}
其中Messager
是被继承的,MessagerImpl
是指针被调用的,(由于MessagerImpl
在类里又是重复的,应该往父类里提,Go有点不好实现,暂时没提)。
package bridge
import (
"fmt"
"image"
)
type Messenger interface {
Login(username string, password string)
SendMessage(message string)
SendPicture(image image.Image)
}
type MessageImp interface {
PlaySound()
DrawShape()
WriteText()
Connect()
}
// 平台实现
type PCMessagerImplementation struct {
MessageImp
}
func (messager *PCMessagerImplementation) PlaySound() {
//PC ...
fmt.Println("PCMessagerImplementation PlaySound")
}
func (messager *PCMessagerImplementation) DrawShape() {
//PC ...
fmt.Println("PCMessagerImplementation DrawShape")
}
func (messager *PCMessagerImplementation) WriteText() {
//PC ...
fmt.Println("PCMessagerImplementation WriteText")
}
func (messager *PCMessagerImplementation) Connect() {
//PC ...
fmt.Println("PCMessagerImplementation Connect")
}
type MobileMessagerImplementation struct {
MessageImp
}
func (messager *MobileMessagerImplementation) PlaySound() {
//Mobile ...
fmt.Println("MobileMessagerImplementation PlaySound")
}
func (messager *MobileMessagerImplementation) DrawShape() {
//Mobile ...
fmt.Println("MobileMessagerImplementation DrawShape")
}
func (messager *MobileMessagerImplementation) WriteText() {
//Mobile ...
fmt.Println("MobileMessagerImplementation WriteText")
}
func (messager *MobileMessagerImplementation) Connect() {
//Mobile ...
fmt.Println("MobileMessagerImplementation Connect")
}
// 业务抽象
type MessagerLite struct {
Messenger //继承
impl MessageImp //实现指针
}
func (lite *MessagerLite) Login(username string, password string) {
lite.impl.Connect()
//...
}
func (lite *MessagerLite) SendMessage(message string) {
lite.impl.WriteText()
}
func (lite *MessagerLite) SendPicture(image image.Image) {
lite.impl.DrawShape()
}
type MessagerPerfect struct {
Messenger //继承
impl MessageImp //实现指针
}
func (perfect *MessagerPerfect) Login(username string, password string) {
perfect.impl.PlaySound()
//...
perfect.impl.Connect()
//...
}
func (perfect *MessagerPerfect) SendMessage(message string) {
perfect.impl.PlaySound()
//...
perfect.impl.WriteText()
//...
}
func (perfect *MessagerPerfect) SendPicture(image image.Image) {
perfect.impl.PlaySound()
//...
perfect.impl.DrawShape()
//..
}
此时类的个数变为1+m+n
,但实现的功能是m*n
测试
package bridge
import "testing"
func TestMessagerImplPrefect(t *testing.T) {
//运行时装配,组合思想
//实现类
var impl MessageImp
impl = &PCMessagerImplementation{}
//实例化
var messager Messenger
messager = &MessagerPerfect{impl: impl}
messager.Login("Hello", "World")
impl = &MobileMessagerImplementation{}
messager = &MessagerLite{impl: impl}
messager.Login("Mobile", "123456")
}
最终可用通过Messager
提供统一的调用方法,而具体的实现根据MessagerImp
抽象了出来,这样实现了m*n
的功能。主要是因为平台
的扩展,和业务
的扩展,应该分开。