Método de fábrica del patrón de diseño VBA
Hay 4 relaciones entre objetos:
-
La relación de agregación
A tiene una B, por ejemplo, el aeropuerto tiene un avión. -
La relación de combinación
A se compone de B, A contiene B y B es parte de A, se expresa como A tiene B, por ejemplo: el avión tiene un motor. -
La relación de herencia
A deriva de B, B es una especie de A y A es una generalización de B, lo que significa que B es A. Por ejemplo: Boeing 777 es un avión. -
La dependencia
A depende de B, y A usa B, se expresa como A usa a B. Por ejemplo: avión usa un piloto.
Mecanismo orientado a objetos de VBA
En VBA, no hay un mecanismo de herencia, pero no importa, porque puede usar la composición para compensar. La clave de la programación orientada a objetos es la clase, porque la clase es el plano del objeto, que es la clave de la programación orientada a objetos.
Cuatro características del título orientado a objetos: (POO)
- Abstracción Abstracción
Escribir código es en realidad un proceso abstracto, cuyas funciones abstraen una serie de operaciones ejecutables. Un módulo abstrae un conjunto de operaciones relacionadas, una clase abstrae un conjunto de datos y operaciones relacionadas, e incluso las variables son una abstracción.
El código claramente estructurado opera en un solo nivel abstracto y llama a otras funciones encapsuladas En un nivel superior, no nos preocupan los detalles de implementación subyacentes.
La clase es una abstracción importante: la clase define la plantilla del objeto, y el objeto encapsula los datos y publica los métodos para operar los datos. - Encapsulación La encapsulación
es similar a la abstracción: encapsula los detalles de implementación y solo publica la interfaz para uso externo. Las variables globales son lo opuesto a la encapsulación. Si hay un campo público en el módulo de clase, no está encapsulando sus datos. No es necesario exponer campos en programación, sino exponer atributos. Los descriptores de acceso a atributos pueden contener código lógico, que es la belleza de la encapsulación. - Polimorfismo
Si nunca antes ha utilizado una interfaz, es difícil entender el polimorfismo. La interfaz permite que VBA abra la puerta a la programación orientada a objetos. Los objetos tienen múltiples formas de habilidades, llamadas polimorfismo. - Herencia
VBA no tiene un mecanismo de herencia. Una clase tiene la capacidad de heredar miembros de otra clase. Cuando dos clases están relacionadas de una manera is-a, la herencia funciona. La herencia es uno de los cuatro pilares de OPP, pero la combinación no lo es. La interfaz VBA es una clase con miembros vacíos.
combinación
En VBA, la relación entre clases no es es-a, sino algo que esta clase tiene-a. Cuando un objeto encapsula instancias de otros objetos, hace uso de grupos. Es posible encapsular objetos externos y exponerlos para simular completamente la herencia de clases.
Propósito de la encapsulación
De forma predeterminada, las clases de VBA son privadas y solo se pueden usar en el proyecto donde están definidas. Las propiedades del módulo de clase también se pueden configurar como "PublicNotCreatable" y usarse en otros proyectos. Otros proyectos agregarán este proyecto VBA como referencia (como hacer referencia a una biblioteca de scripts, ahora haciendo referencia a otro .xlsm o .xlam). En el proyecto de VBA al que se hace referencia, puede ver y usar las clases en otros proyectos a los que se hace referencia, pero no puede crear sus instancias. Se necesita una forma de exponer la funcionalidad al proyecto de VBA al que se hace referencia para devolver una instancia de la clase pública.
Modo de columna única singleton
En el patrón de diseño OOP, el método de fábrica se usa generalmente en combinación con el patrón de una sola columna, porque la clase de fábrica solo necesita tener una instancia. Si el cliente no puede usar la palabra clave New para crear una instancia de clase, establecer la propiedad VB_PredeclaredId en True esencialmente hace que la instancia predeterminada de la clase sea un singleton válido.
Instancia predeterminada en VBA
Primero exporte un módulo de clase VBA, luego ábralo con el Bloc de notas, verá las siguientes propiedades:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "类1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
En el módulo de formulario de VBA, hay una instancia predeterminada, debido a que el atributo se establece en Verdadero en el módulo de formulario, este atributo de VBA crea automáticamente un objeto de alcance global. Exporte el módulo de formulario de la misma manera y ábralo con el Bloc de notas.
VERSION 5.00
Begin {C62A69F0-16DC-11CE-9E98-00AA00574A4F} UserForm1
Caption = "UserForm1"
ClientHeight = 3015
ClientLeft = 120
ClientTop = 465
ClientWidth = 4560
OleObjectBlob = "UserForm1.frx":0000
StartUpPosition = 1 '所有者中心
End
Attribute VB_Name = "UserForm1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True '该属性是打开VBA面向对象编程的关键
Attribute VB_Exposed = False
Puede usar UserForm1.Show directamente al mostrar el formulario. La instancia de UserForm1 creada no se muestra y se usa una instancia existente. Porque crea automáticamente un objeto global predeterminado con el nombre de la clase, al igual que una clase estática.
Use la instancia predeterminada como el modo de una sola columna en VBA, este atributo es la clave para abrir la programación de VBA OOP. Con este atributo, podemos tener un objeto de solo lectura válido en VBA.
ejemplo
Si tiene una clase de automóvil, hay tres atributos de marca, modelo y fabricante en la clase, a saber, tiempo de fabricación, modelo de automóvil y fabricante.
'@Folder("VBAProject")
'@Class Car
Option Explicit
Private Type TCar
Make As Long
Model As String
Manufacturer As String
End Type
Private this As TCar
Public Property Get Make() As Long
Make = this.Make
End Property
Friend Property Let Make(ByVal Value As Long)
this.Make = Value
End Property
Public Property Get Model() As String
Model = this.Model
End Property
Friend Property Let Model(ByVal Value As String)
this.Model = Value
End Property
Public Property Get Manufacturer() As String
Manufacturer = this.Manufacturer
End Property
Friend Property Let Manufacturer(ByVal Value As String)
this.Manufacturer = Value
End Property
La palabra clave Friend pasa a ser de solo lectura para los elementos de referencia externa. La clase CarFactory definida en el mismo proyecto puede acceder a los datos modificados por Friend.
'@Exposed
'@Folder("VBAProject")
'@PredeclaredId=True
'@ClassName CarFactory
Option Explicit
Public Function Create(ByVal carMake As Long, ByVal carModel As String, ByVal carManufacturer As String) As Car
Dim result As Car
Set result = New Car
With New result
.Make = carMake
.Model = carModel
.Manufacturer = carManufacturer
End With
Set Create = result
End Function
La función PredeclaredId de CarFactory se establece en True, y el código de cliente VBA puede llamar a esta clase de esta manera.
Public Sub DoSomething()
Dim myCar As Car
Set myCar = CarFactory.Create(2020, "Civic", "Honda")
Debug.Print "We hav a " & myCar.Make & " " & myCar.Manufacturer & " " & myCar.Model & " here."
End Sub
Interfaz en VBA
En VBA, los miembros públicos de un módulo de clase definen la interfaz predeterminada de la instancia de clase. En teoría, cualquier otra clase puede implementar la interfaz predeterminada de cualquier otra clase. En la práctica, los módulos de clase se utilizan para definir interfaces abstractas formales (solo códigos auxiliares de métodos sin implementación), y estas clases especiales se denominan interfaces.
Por ejemplo, agregue un módulo de clase y utilícelo como una interfaz denominada ICar.
'@Interface
'@Folder("VBAProject")
'@ClassName ICar
Option Explicit
Public Property Get Make() As Long
End Property
Public Property Get Model() As String
End Property
Public Property Get Manufacturer() As String
End Property
Implementar interfaz en VBA
En VBA, la palabra clave Implements se usa en la parte de declaración del módulo de clase para decirle al compilador que la clase se puede usar con una interfaz específica. Pero cada miembro de la interfaz debe implementarse y se producirán errores de compilación si no se implementan.
Por lo tanto, el código anterior tiene una interfaz abstracta ICar. Indica que cualquier objeto que implemente esta interfaz tiene atributos de solo lectura Marca, Modelo y Fabricación.
'@Folder("VBAProject")
'@PredeclaredId
'@ClassName ReadOnlyCar
Option Explicit
Implements ICar
Private Type TCar
Make As Long
Model As String
Manufacture As String
End Type
Private this As TCar
Private Property Get ICar_Make() As Long
ICar_Make = this.Make
End Property
Private Property Get ICar_Model() As String
ICar_Model = this.Model
End Property
Private Property Get ICar_Manufacturer() As String
ICar_Manufacturer = this.Manufacture
End Property
Tenga en cuenta que el código de implementación es siempre privado y no se puede cambiar. Estos métodos no son públicos en instancias de clases. Solo se puede acceder a estos métodos a través de ICar.
Moví el método Create de la clase de fábrica a la propia clase ReadOnlyCar y la función devuelve la interfaz ICar
Public Function Create(ByVal carMake As Long, ByVal carModel As String, ByVal carManufacturer As String) As ICar
With this
.Make = carMake
.Model = carModel
.Manufacturer = carManufacturer
End With
Set Create = Me
End Function
Debido a que la propiedad VB_PredeclaredId de la clase está establecida en True, obtendrá una instancia predeterminada global gratuita. El código de cliente se puede utilizar así.
Dim myCar as ICar
set myCar=ReadOnlyCar.Create(2020,"Honda","Fit")
'在这里mycar只能访问ICar的成员。
Es muy problemático para cada clase de implementación proporcionar los métodos anteriores. Redefinir una interfaz de fábrica abstracta ICarFactory.
'@Folder("VBAProject")
'@Interface
Option Explicit
Public Function Create(ByVal carMake As Long, ByVal carModel As String, ByVal carManufacturer) As ICar
End Function
ICar implementa esta interfaz, el código se simplifica y el método Create original se elimina. el código se muestra a continuación:
'@Folder("VBAProject")
'@Class Car
Option Explicit
Implements ICar
Implements IFactory
Private Type TCar
Make As Long
Model As String
Manufacturer As String
End Type
Private this As TCar
Public Property Get Self() As IFactory
Set Self = Me
End Property
Private Property Get ICar_Make() As Long
'TODO implement interface member
ICar_Make = this.Make
End Property
Private Property Get ICar_Model() As String
'TODO implement interface member
ICar_Model = this.Model
End Property
Private Property Get ICar_Manufacturer() As String
'TODO implement interface member
ICar_Manufacturer = this.Manufacturer
End Property
Private Function IFactory_Create(ByVal carMake As Long, ByVal carModel As String, ByVal carManufacturer As Variant) As ICar
With this
.Make = carMake
.Model = carModel
.Manufacturer = carManufacturer
End With
Set IFactory_Create = Me
End Function
El código del cliente se implementa de la siguiente manera, que se vuelve muy conciso.
Public Sub main()
Dim myCar As ICar
Set myCar = ReadOnlyCar.Self.Create(2020, "丰田", "上汽")
Debug.Print myCar.Make, myCar.Manufacturer, myCar.Model
End Sub
Lo anterior es el método de fábrica implementado en VBA, que puede implementar operaciones de inicialización de objetos VBA y simular constructores de lenguaje de alto nivel.
Definición de método de fábrica
Defina una interfaz para crear objetos y deje que la subclase decida qué clase instanciar. Los métodos de fábrica retrasan la instanciación de una clase a sus subclases.
Diagrama de clases general del patrón del método de fábrica
En el patrón del método de fábrica, la clase de producto abstracto Product es responsable de definir la similitud de los productos y realizar la definición abstracta más alta de las cosas; Creator es una clase de creación abstracta, es decir, una fábrica abstracta. Cómo crear una clase de producto está hecho por la fábrica de realización de hormigón ConcreteCreateor.
Tomemos como ejemplo la historia de la creación de seres humanos por parte de Nuwa:
según el color de la piel, cree personas de protección de diferentes colores.
El primer paso: de
acuerdo con la semántica del método de fábrica, primero se encuentra lo común de los seres humanos. El color de la piel humana y las diferentes sílabas del habla se abstraen y publican como una interfaz.
'@Interface IHuman
Publci Sub getColor()
'皮肤颜色不同
End sub
public Sub talk()
'说法方式不同
End sub
'@不同护色的人实现该接口
'@YelloHuman
Implements IHuman
Private Sub IHuman_getColor()
Debug.Print "黄色人种的皮肤颜色是黄色的!"
End Sub
Private Sub IHuman_talk()
Debug.Print "黄色人种会说话,一般说的都是双字节。"
End Sub
'@WhiteHuman
Private Sub IHuman_getColor()
Debug.Print "白色人种的皮肤颜色是白色的!"
End Sub
Private Sub IHuman_talk()
Debug.Print "白色人种会说话,一般都是单字节。"
End Sub
'@BlackHuman
Private Sub IHuman_getColor()
Debug.Print "黑色人种的皮肤颜色是黑色的!"
End Sub
Private Sub IHuman_talk()
Debug.Print "黑人会说话,一般听不懂"
End Sub
El código VBA anterior ha completado la definición de la parte más abstracta de las cosas según la semántica del método de fábrica.
'@Interface IAbstractFactory
public Function CreateObject(Value as IHuman) as IHuman
'通过接口来延迟到子类实例化对象
End Function
'AbstactFactory
Implements AbstactHumanFactory
Public Property Get Self() As IAbstactFactory
Set Self = Me
End Property
Private Function AbstactFactory_CreateOject(Value As IHuman) As IHuman
Set AbstactFactory_CreateOject = Value
End Function