03_单一职责模式

news2024/11/23 19:15:15

单一职责

在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。

装饰模式

动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,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扩展。代码重复度过高。每次都继承,可以看到有这么多类

Stream
+Read(nums)
+Seek(position)
+Write(data)
FileStream
- Stream
+Read(nums)
+Seek(position)
+Write(data)
NetworkStream
- Stream
+Read(nums)
+Seek(position)
+Write(data)
MemoryStream
- Stream
+Read(nums)
+Seek(position)
+Write(data)
CryptoFileStream
- fs: FileStream
+Read(nums)
+Seek(position)
+Write(data)
CryptoNetworkStream
- ns: NetworkStream
+Read(nums)
+Seek(position)
+Write(data)
CryptoMemoryStream
- ms: MemoryStream
+Read(nums)
+Seek(position)
+Write(data)
BufferedFileStream
- fs: FileStream
+Read(nums)
+Seek(position)
+Write(data)
BufferedNetworkStream
- ns: NetworkStream
+Read(nums)
+Seek(position)
+Write(data)
BufferedMemoryStream
- ms: MemoryStream
+Read(nums)
+Seek(position)
+Write(data)
CryptoBufferedFileStream
- cfs: CryptoFileStream
+Read(nums)
+Seek(position)
+Write(data)
CryptoBufferedNetworkStream
- nfs: CryptoNetworkStream
+Read(nums)
+Seek(position)
+Write(data)
CryptoBufferedMemoryStream
- mfs: CryptoMemorykStream
+Read(nums)
+Seek(position)
+Write(data)

可见这类的增长深度是有多块,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")
}

Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
FileStream
- Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
NetworkStream
- Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
MemoryStream
- Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
CryptoStream
- stream: Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
BufferedStream
- stream: Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
CryptBufferedStream
- stream: Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)

图不一定标准,具体使用,可以通过组合实现想要的功能

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)
}

类图

Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
FileStream
- Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
NetworkStream
- Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
MemoryStream
- Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
DecorateStream
- Stream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
CryptoStream
- DecorateStream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)
BufferedStream
- DecorateStream
+Read(nums: int)
+Seek(position: int)
+Write(data: byte)

这样类的个数是1+n+m.

总结

组合由于继承!

类图,同时想要继承和组合同一个对象,大概率是装饰模式。

在这里插入图片描述

  • 通过采用组合而非继承的手法, Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
  • Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。
  • Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。

桥模式

将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。

动机:

  • 由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。
  • 如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?

实现

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{}

类图

Messager
+Login(username: string, password: string)
+SendMessage(message: string)
+SendPicture(image: image.Image)
+PlaySound()
+DrawShape()
+WriteText()
+Connect()
PCMessagerBase
- Messager
+PlaySound()
+DrawShape()
+WriteText()
+Connect()
MobileMessagerBase
- Messager
+PlaySound()
+DrawShape()
+WriteText()
+Connect()
PCMessagerLite
- PCMessagerBase
+Login(username: string, password: string)
+SendMessage(message: string)
+SendPicture(image: image.Image)
MobileMessagerLite
- MobileMessagerBase
+Login(username: string, password: string)
+SendMessage(message: string)
+SendPicture(image: image.Image)
PCMessagerPerfect
- PCMessagerBase
+Login(username: string, password: string)
+SendMessage(message: string)
+SendPicture(image: image.Image)
MobileMessagerPerfect
- MobileMessagerBase
+Login(username: string, password: string)
+SendMessage(message: string)
+SendPicture(image: image.Image)

这样的话,假设业务抽象有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")
}

Messenger
+Login(username, password)
+SendMessage(message)
+SendPicture(image)
MessageImp
+PlaySound()
+DrawShape()
+WriteText()
+Connect()
PCMessagerImplementation
+PlaySound()
+DrawShape()
+WriteText()
+Connect()
MobileMessagerImplementation
+PlaySound()
+DrawShape()
+WriteText()
+Connect()
MessagerLite
- Messenger
- MessageImp
+Login(username, password)
+SendMessage(message)
+SendPicture(image)
MessagerPerfect
- Messenger
- MessageImp
+Login(username, password)
+SendMessage(message)
+SendPicture(image)

最终可用通过Messager提供统一的调用方法,而具体的实现根据MessagerImp抽象了出来,这样实现了m*n的功能。主要是因为平台的扩展,和业务的扩展,应该分开。

总结

在这里插入图片描述

  • Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。
  • Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
  • Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/716942.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

系统没有“internet信息服务(IIS)管理器”

系统没有“internet信息服务(IIS)管理器” 解决方案1.打开控制面板,找到并打开程序。2.找到并打开程序里的启用或关闭windows功能。3.在‘Internet Information Services’下的‘web管理工具’中找到IIS相关功能,在前面的复选框中…

探索数字孪生世界:市场上五款炙手可热的数字孪生产品介绍

山海鲸可视化:山海鲸可视化是一款国内领先的数字孪生软件,具有强大的GIS功能和可视化效果,广泛应用于城市规划、建筑设计和智慧城市等领域。 华为云数字孪生:华为云数字孪生平台提供了全面的数字化解决方案,包括智慧城…

链表中倒数第k个结点(快慢指针问题)

⭐️ 往期相关文章 💫链接1:leetcode 876.链表的中间结点(快慢指针问题) 💫链接2:leetcode 206.反转链表 💫链接3:leetcode 203.移除链表元素 💫链接4:数据结构-手撕单链表代码详解…

实训笔记7.4

实训笔记7.4 7.4一、座右铭二、IDEA集成开发环境的安装和使用三、DEBUG断点调试四、Java设计模式4.1 适配器模式4.2 动态代理模式4.3 单例设计模式 五、Java中网络编程5.1 网络编程三个核心要素5.2 TCP网络编程 六、基于网络编程的聊天系统6.1 需求分析6.2 系统设计6.2.1 概要设…

解放运营人员:钡铼技术S475物联网网关实现养殖环境的远程监控与告警

在养殖行业中,对环境参数的精确监测与控制至关重要。然而,传统的监测方法往往存在诸多痛点,如数据采集不准确、传输速度慢、可视化效果差等。为了解决这些问题,钡铼技术公司推出了其旗舰产品——S475多功能RTU,该产品在…

如何利用思维导图提高项目管理效率

思维导图 是一种强大的工具,可以帮助我们更好地组织和管理项目。它是一种以图形方式展现思维和概念之间关系的方法,通过将主题、子主题和分支串联起来,帮助我们清晰地了解任务的层次结构和相互关系。在项目管理中,思维导图可以帮助…

数据生成实体类解决方案

文章目录 数据生成实体类解决方案 简介工作原理解析JSON生成实体类示例JSON消息解析JSON核心方法:调用示例:将数据保存到实体类中。将实体类转为输出为JSON。 思考 数据生成实体类解决方案 直接将xml导入到Studio里即可。下载文件连接: CSDN…

GPIO点灯

简述:本人使用教材为《嵌入式系统原理与应用》,GPIOCON控制输出,GPIODAT控制高电平和低电平,高电平点亮,低电平熄灭。

【若依】框架搭建,前端向后端如何发送请求,验证码的实现

若依框架 若依框架(Ruoyi)是一款基于Spring Boot和Spring Cloud的开源快速开发平台。它提供了一系列的基础功能和通用组件,能够帮助开发者快速构建企业级应用。若依框架采用了模块化的设计理念,用户可以选择需要的功能模块进行集…

全网最全,华为可信专业级认证介绍

1:华为可信专业级认证是什么? 华为在推动技术人员的可信认证,算是一项安全合规的工作。专业级有哪些考试呢?共有四门: 科目一:上级编程,对比力扣2道中等、1道困难; 科目二&#xff…

C++ STL --哈希表

目录 1. unordered系列关联式容器 1.1 unordered_map 1.1.1 unordered_map的文档介绍 1.1.2 unordered_map的接口说明 1.2 unordered_set 1.3 在线OJ 2. 底层结构 2.1 哈希概念 2.2 哈希冲突 2.3 哈希函数 2.4 哈希冲突解决 2.4.1 闭散列 2.4.2 开散列 3. 模拟实现…

中学生用什么样护眼台灯好?适合暑假学习的护眼台灯推荐

终于到了暑假,本来是有大把的“娱乐”时间,可现在看来此“娱乐”和正常出门玩耍的娱乐不太一样。不管是大学生还是中小学生,不少孩子不再出门玩耍,而是宅在家空调WiFi西瓜,抱着手机往那一趴。加上平时还需要抽出时间完…

DatenLord前沿技术分享 No.29

达坦科技专注于打造新一代开源跨云存储平台DatenLord,通过软硬件深度融合的方式打通云云壁垒,致力于解决多云架构、多数据中心场景下异构存储、数据统一管理需求等问题,以满足不同行业客户对海量数据跨云、跨数据中心高性能访问的需求。BSV的…

自动化测试selenium篇(二)

需要掌握selenium 常用API的使用 一、元素定位 1.1css选择器语法 1.1.1 类选择器(class选择器) 语法 : .class属性值{} 作用 : 选中对应class属性值的元素 1.1.2 id选择器 语法 : #id属性值{} 作用 : 选中对应id属性值的元素 1.1.3 标签选择器 标签选择器会选择页面上…

https技术鉴赏

视频网址:https://www.bilibili.com/video/BV1uY4y1D7Ng 总结起来:先使用非对称加密,再使用对称加密,这样就避免了明文传输。 非对称加密的作用是协商对称加密的公钥 SSL流程图大概如下: 这只是一个最简单的SSL版本,…

Small Outline Package(小外形封装)和Quad Flat Package(四边引线扁平封装)

1.Small Outline Package(小外形封装) SOP封装图片 SOP技术是飞利浦公司开发成功,以后逐渐派生出SOJ、TSOP、VSOP、SSOP、TSSOP、SOT、SOIC等封装形式。SOP是表面贴装型封装的一种,引脚从封装两侧引出,呈海鸥状形。其…

JS知识点汇总(十一)--事件模型

1. JavaScript中的事件模型有哪些 1、事件与事件流 javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件、鼠标事件、自定义事件等 由于DOM是一个树结构,如果在父…

《面向分布式云的直播及点播云技术创新方案》获中国信通院“分布式云技术创新先锋案例”

由中国信息通信研究院、中国通信标准化协会主办的第三届“云边协同大会”于 6 月 30 日在京举办。阿里云视频云团队凭借 《面向分布式云的直播及点播云技术创新方案》 在一众产品服务中脱颖而出,荣获「分布式云技术创新先锋案例」。 面向分布式云技术的直播及点播云…

驱动控制STM32LED灯的两秒,亮灭

控制LED灯的亮灭 head.h #ifndef __HEAD_H__ #define __HEAD_H__#define PHY_LED1_MODER 0X50006000 #define PHY_LED1_ODR 0X50006014 #define PHY_LED2_MODER 0X50007000 #define PHY_LED2_ODR 0X50007014 #define PHY_LED3_MODER 0X50006000 #define PHY_LED3_ODR 0X50006…

机器学习17:训练神经网络-反向传播算法

反向传播算法对于快速训练大型神经网络至关重要。本文将介绍算法的工作原理。 目录 1.简单的神经网络 2.激活函数 3.错误函数 4.正向传播 4.1 更新隐藏层 5.反向传播 5.1 求导数 5.2 其他导数 5.3 反向传播误差倒数 6.参考文献 1.简单的神经网络 如图 1 所示&#…