El patrón de diseño (patrón de diseño) es un conjunto de resúmenes clasificados y catalogados de la experiencia de diseño de código que se utiliza repetidamente y es conocido por la mayoría de las personas.
Los patrones de diseño se dividen en tres tipos, con un total de 23 tipos:
Escrito con referencia a artículos de Hongyang, tutoriales para novatos, etc. Corríjame si hay algún error. Si hay alguna infracción, comuníquese conmigo para eliminarla.
1. Patrón de diseño Patrón de observador (Patrón de observador) Tomando el servicio público WeChat como ejemplo
2. Design Pattern Factory Pattern (Patrón de fábrica) comienza con la venta de Roujiamo
3. Análisis completo del patrón de diseño Singleton (patrón Singleton)
4. Patrón de diseño El patrón de estrategia (Patrón de estrategia) toma los juegos de rol como fondo
5. Patrón de diseño Patrón de adaptador (Patrón de adaptador) Tome el cargador de teléfono móvil como ejemplo
6. Patrón de comando de patrón de diseño para administrar electrodomésticos inteligentes
7. Design Pattern Decorator Pattern te lleva de regreso al mundo legendario
8. Modo de diseño, modo de apariencia (Patrón de fachada) modo de película con un clic
9. Patrón de diseño Patrón de método de plantilla muestra el día de un programador
10. Patrón de diseño Patrón de estado (Patrón de estado) Tome una máquina expendedora como ejemplo
11. Patrón de diseño Patrón de construcción (Patrón de construcción) Tome como ejemplo la construcción de un automóvil y la compra de un automóvil.
12. Patrón de diseño Patrón de prototipo (Patrón de prototipo) Tome la obtención de múltiples formas como ejemplo.
13. Patrón de diseño Flyweight Pattern (Patrón Flyweight) toma como ejemplo la obtención aleatoria de múltiples formas
14. Patrón de diseño Patrón proxy (Patrón proxy) Tome la obtención de imágenes del disco como ejemplo.
15. Patrón de diseño Patrón de puente (Patrón de puente) Tome como ejemplo dibujar círculos de diferentes colores
16. Patrón de combinación de patrones de diseño (patrón compuesto) Tome como ejemplo la creación e impresión de la jerarquía de empleados
17. Patrón de diseño Patrón iterador (Patrón iterador) Tome el uso de un iterador para imprimir nombres como ejemplo.
18. Patrón de diseño Patrón mediador (Patrón mediador) Tomando salas de chat públicas como ejemplo
19. Patrón de diseño Patrón Memento (Patrón Memento) Tome Memento como ejemplo
20. Patrón de diseño Patrón de intérprete (Patrón de intérprete) Tome la explicación de una oración como ejemplo.
21. Patrón de diseño de cadena de responsabilidad (Patrón de cadena de responsabilidad) Tome los registros de impresión en Android Studio como ejemplo
22. Patrón de diseño Patrón de visitante (Patrón de visitante) Tome la visualización de los componentes de la computadora como ejemplo.
- Observador
- Fábrica
- Semifallo
- Estrategia
- Adaptador
- Dominio
- Decorador
- Fachada
- Método de plantilla
- Estado
- Constructor
- Prototipo
- peso mosca
- Apoderado
- Puente
- Compuesto
- Iterador
- Mediador
- Recuerdo
- Cadena de Responsabilidad
- Visitante
Define dependencias de uno a muchos entre objetos, de modo que cuando un objeto cambia, todas sus dependencias serán notificadas y actualizadas automáticamente.
Hay muchos lugares en JDK o Andorid que implementan el patrón de observador, como XXXView.addXXXListenter. Por supuesto, XXXView.setOnXXXListener no es necesariamente el patrón de observador, porque el patrón de observador es una relación de uno a muchos, y para setXXXListener, es un par. La relación entre 1 y 1 debería llamarse devolución de llamada.
Interfaz especial: Asunto.java;
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
Clase de implementación de cuenta de servicio 3D: ObjectFor3D.java
@ Override
public void registerObserver ( Observer observer ) {
observers . add ( observer );
}
@ Override
public void removeObserver ( Observer observer ) {
int index = observers . indexOf ( observer );
if ( index >= 0 ) {
observers . remove ( index );
}
}
@ Override
public void notifyObservers () {
for ( Observer observer : observers ) {
observer . update ( msg );
}
}
/**
* 主题更新信息
*/
public void setMsg ( String msg ) {
this . msg = msg ;
notifyObservers ();
}
Todos los observadores deben implementar esta interfaz: Observer.java
public ObserverUser1 ( Subject subject ) {
subject . registerObserver ( this );
}
@ Override
public void update ( String msg ) {
Log . e ( "-----ObserverUser1 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
Prueba final: ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
Enumeremos brevemente la familia de este patrón:
1. Modo de fábrica estático
2. Modo de fábrica simple (comprar Roujiamo en la tienda)
public RoujiaMo creatRoujiaMo ( String type ) {
RoujiaMo roujiaMo = null ;
switch ( type ) {
case "Suan" :
roujiaMo = new ZSuanRoujiaMo ();
break ;
case "La" :
roujiaMo = new ZLaRoujiaMo ();
break ;
case "Tian" :
roujiaMo = new ZTianRoujiaMo ();
break ;
default : // 默认为酸肉夹馍
roujiaMo = new ZSuanRoujiaMo ();
break ;
}
return roujiaMo ;
}
3. Modelo de método de fábrica (apertura de sucursal)
Proporciona métodos abstractos para crear Roujia MoStore: RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
Implementación específica del método abstracto: XianRoujiaMoStore.java
La sucursal todavía usa el modelo de fábrica simple: XianSimpleRoujiaMoFactory.java
4. Patrón abstracto de fábrica (utilizando materias primas oficiales)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
El modo singleton es principalmente para evitar el desperdicio de recursos causado por la creación de múltiples instancias, y múltiples instancias pueden conducir fácilmente a resultados incorrectos debido a múltiples llamadas. El uso del modo singleton puede garantizar que solo haya una instancia en toda la aplicación .
Definición: Sólo se necesitan tres pasos para garantizar la unicidad de un objeto.
Comparar definición:
Estilo Hungry Han [disponible]: SingletonEHan.java
Contiene estilo Han perezoso [se recomienda bloqueo de doble verificación]: SingletonLanHan.java
private SingletonLanHan () {}
private static SingletonLanHan singletonLanHanFour ;
public static SingletonLanHan getSingletonLanHanFour () {
if ( singletonLanHanFour == null ) {
synchronized ( SingletonLanHan . class ) {
if ( singletonLanHanFour == null ) {
singletonLanHanFour = new SingletonLanHan ();
}
}
}
return singletonLanHanFour ;
}
Patrón de estrategia: define una familia de algoritmos y los encapsula por separado para hacerlos intercambiables. Este patrón permite que los cambios de algoritmo sean independientes de los clientes que los utilizan.
RoleA roleA = new RoleA ( "---A" );
roleA . setiDisplayBehavior ( new DisplayYZ ())
. setiAttackBehavior ( new AttackXL ())
. setiDefendBehavior ( new DefendTMS ())
. setiRunBehavior ( new RunJCTQ ());
roleA . display (); // 样子
roleA . attack (); // 攻击
roleA . run (); // 逃跑
roleA . defend (); // 防御
Definición: convertir la interfaz de una clase en otra interfaz esperada por el cliente. El adaptador permite que clases con interfaces incompatibles cooperen entre sí. Esta definición está bien, diciendo que la función de un adaptador es convertir una interfaz en otra interfaz.
Tomemos el cargador como ejemplo: los cargadores de teléfonos móviles generalmente tienen alrededor de 5 V. El voltaje de CA de nuestro hogar en China es de 220 V, por lo que la carga de teléfonos móviles requiere un adaptador (reductor de voltaje).
Un teléfono móvil: Mobile.java
El teléfono depende de una interfaz que proporciona un voltaje de 5 V: V5Power.java
Lo que tenemos es CA doméstica de 220 V: V220Power.java
Adaptador para completar la función de convertir 220V a 5V : V5PowerAdapter.java
Prueba final: Cargue el teléfono:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
Definición: encapsule "solicitudes" en objetos para que otros objetos puedan parametrizarse utilizando diferentes solicitudes, colas o registros. El modo de comando también admite operaciones que se pueden deshacer. (Simplificación: encapsule la solicitud en un objeto y desacople el solicitante de la acción y el ejecutor de la acción).
QuickCommand quickCloseCommand = new QuickCommand ( new Command []{ new LightOffCommand ( light ), new ComputerOffCommand ( computer ), new DoorCloseCommand ( door )});
controlPanel . setCommands ( 6 , quickOpenCommand );
controlPanel . keyPressed ( 6 );
controlPanel . setCommands ( 0 , new DoorOpenCommand ( door )); // 开门
controlPanel . keyPressed ( 0 );
Patrón decorador: para ampliar la funcionalidad, los decoradores proporcionan una alternativa más flexible a la integración, asignando dinámicamente responsabilidades a los objetos.
Describamos brevemente dónde entra en juego el patrón decorador. Cuando diseñamos una clase, necesitamos agregar algunas funciones auxiliares a esta clase y no queremos cambiar el código de esta clase. Aquí es cuando entra en juego el patrón decorador. jugar. Es hora. Esto también refleja un principio: las clases deben estar abiertas a ampliaciones y cerradas a modificaciones.
Requisitos: Diseñar el sistema de equipamiento del juego. El requisito básico es poder calcular el poder de ataque y la descripción de cada equipo después de incrustarlo con varias gemas:
1. Superclase de equipo: IEquip.java
2. Clases de implementación de cada equipo:
3. Superclase de decoraciones (las decoraciones también pertenecen al equipo): IEquipDecorator.java
4. Clase de implementación de decoraciones:
5. Prueba final: calcule el poder de ataque y vea la descripción:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
Definición: proporciona una interfaz unificada para acceder a un grupo de interfaces en el subsistema. La apariencia define una interfaz de alto nivel para que el subsistema sea más fácil de usar. De hecho, para comodidad de los clientes, un grupo de operaciones se encapsula en un método.
Demanda: Prefiero ver películas, así que compré un proyector, una computadora, un estéreo, diseñé la iluminación de la habitación y compré una máquina de palomitas de maíz. Luego, cuando quiero ver una película, necesito verla y apagarla con un solo clic. .
Cambio y otras operaciones para cada clase de dispositivo:
por ejemplo: Máquina de palomitas de maíz: PopcornPopper.java
Clase de cine: HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
Prueba final: visualización de películas con un clic:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
Definición: define el esqueleto de un algoritmo y difiere algunos pasos a las subclases. El método de plantilla permite a las subclases redefinir los pasos del algoritmo sin cambiar la estructura del algoritmo.
Requisitos: Describa brevemente: Nuestra empresa cuenta con programadores, evaluadores, recursos humanos, gerentes de proyectos, etc. El modo de método de plantilla se utiliza a continuación para registrar el estado laboral de todo el personal.
Tres tipos de roles en el patrón del método de plantilla
1. Método concreto
2. Método abstracto
3. Método del gancho
Superclase de trabajador: Worker.java
// 具体方法
public final void workOneDay () {
Log . e ( "workOneDay" , "-----------------work start----------------" );
enterCompany ();
work ();
exitCompany ();
Log . e ( "workOneDay" , "-----------------work end----------------" );
}
// 工作 抽象方法
public abstract void work ();
// 钩子方法
public boolean isNeedPrintDate () {
return false ;
}
private void exitCompany () {
if ( isNeedPrintDate ()) {
Log . e ( "exitCompany" , "---" + new Date (). toLocaleString () + "--->" );
}
Log . e ( "exitCompany" , name + "---离开公司" );
}
Clase de implementación del programador (se puede conocer el tiempo): ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
Prueba final:
Mira cómo están trabajando todos:
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
Compruebe cuándo el programador dejó la empresa:
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
Definición: Permite que un objeto cambie su comportamiento cuando cambia su estado interno, haciendo que el objeto parezca como si hubiera modificado su clase.
La definición está empezando a ser borrosa nuevamente. Piénselo. Cuando el estado interno de un objeto cambia, su comportamiento cambia con el cambio de estado. Parece que uno similar se reinicia.
Requisitos: tome una máquina expendedora como ejemplo (hay estados como moneda insertada y no insertada, y métodos para insertar y devolver monedas)
Implementación inicial de la máquina expendedora a mejorar: VendingMachine.java
Máquina expendedora mejorada (más maleable): VendingMachineBetter.java
// 放钱
public void insertMoney () {
currentState . insertMoney ();
}
// 退钱
public void backMoney () {
currentState . backMoney ();
}
// 转动曲柄
public void turnCrank () {
currentState . turnCrank ();
if ( currentState == soldState || currentState == winnerState ) {
currentState . dispense (); //两种情况会出货
}
}
// 出商品
public void dispense () {
Log . e ( "VendingMachineBetter" , "---发出一件商品" );
if ( count > 0 ) {
count --;
}
}
// 设置对应状态
public void setState ( State state ) {
this . currentState = state ;
}
Interfaz de estado: State.java
Clase de implementación de interfaz correspondiente al estado:
Prueba de máquina expendedora mejorada:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
El modo de construcción es el modo de creación de objetos. El modo de construcción puede separar la representación interna de un producto del proceso de producción del producto, de modo que un proceso de construcción puede generar objetos de producto con diferentes representaciones internas.
Requisitos: Los usuarios acuden a una tienda de automóviles para comprar un automóvil.
Análisis: El taller de coches extrae los coches correspondientes según las necesidades de cada usuario
Superclase de constructor: Constructor
public abstract class Builder {
public abstract void setPart ( String name , String type );
public abstract Product getProduct ();
}
Clase de implementación correspondiente al constructor: ConcreteBuilder
public class ConcreteBuilder extends Builder {
private Product product = new Product ();
@ Override
public void setPart ( String name , String type ) {
product . setName ( name );
product . setType ( type );
}
@ Override
public Product getProduct () {
return product ;
}
}
El encargado de la tienda recoge el coche:
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
El patrón prototipo se utiliza para crear objetos repetidos y al mismo tiempo garantizar el rendimiento. Este tipo de patrón de diseño es un patrón de creación que proporciona una forma óptima de crear objetos.
Este patrón implementa una interfaz prototipo que se utiliza para crear un clon del objeto actual. Este modo se utiliza cuando el costo de crear objetos directamente es relativamente alto. Por ejemplo, es necesario crear un objeto después de una costosa operación de base de datos. Podemos almacenar en caché el objeto, devolver un clon del mismo en la siguiente solicitud y actualizar la base de datos cuando sea necesario para reducir las llamadas a la base de datos.
Tomando como ejemplo la obtención de múltiples formas, hay cuatro pasos:
1. Cree una clase abstracta que implemente la interfaz Cloneable. Forma (implementa clonable)
public abstract class Shape implements Cloneable {
private String id ;
protected String type ;
public abstract void draw ();
public String getId () {
return id ;
}
public void setId ( String id ) {
this . id = id ;
}
@ Override
public Object clone () {
Object object = null ;
try {
object = super . clone ();
} catch ( CloneNotSupportedException e ) {
Log . e ( "--" , e . getMessage ());
}
return object ;
}
}
2. Cree una clase de entidad que extienda la clase abstracta anterior. Círculo, Rectángulo, Cuadrado
public class Circle extends Shape {
public Circle () {
type = "Circle" ;
}
@ Override
public void draw () {
Log . e ( "---" , "Inside Circle::draw() method." );
}
}
3. Cree una clase para obtener clases de entidad de la base de datos y almacenarlas en una Hashtable. caché de formas
public class ShapeCache {
private static Hashtable < String , Shape > shapeMap = new Hashtable < String , Shape >();
public static Shape getShape ( String shapeId ) {
Shape shapeCache = shapeMap . get ( shapeId );
return ( Shape ) shapeCache . clone ();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
public static void loadCache () {
Circle circle = new Circle ();
circle . setId ( "1" );
shapeMap . put ( circle . getId (), circle );
Rectangle rectangle = new Rectangle ();
rectangle . setId ( "2" );
shapeMap . put ( rectangle . getId (), rectangle );
Square square = new Square ();
square . setId ( "3" );
shapeMap . put ( square . getId (), square );
}
}
4. Utilice la clase ShapeCache para obtener un clon de la forma almacenada en Hashtable.
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
Se utiliza principalmente para reducir la cantidad de objetos creados para reducir el uso de memoria y mejorar el rendimiento. Este tipo de patrón de diseño es un patrón estructural, que proporciona una manera de reducir la cantidad de objetos y así mejorar la estructura de objetos requerida por la aplicación.
El patrón Flyweight intenta reutilizar objetos existentes del mismo tipo o crear nuevos objetos si no se encuentra ningún objeto coincidente. Demostraremos este patrón creando 5 objetos que dibujen 20 círculos en diferentes ubicaciones. Dado que sólo hay 5 colores disponibles, la propiedad de color se utiliza para comprobar el objeto Círculo existente.
Tomando como ejemplo la obtención aleatoria de múltiples formas, hay cuatro pasos:
1. Cree una interfaz.
public interface Shape {
void draw ();
}
2. Cree una clase de entidad que implemente la interfaz.
public class Circle implements Shape {
private String color ;
private int x ;
private int y ;
private int radius ;
public Circle ( String color ) {
this . color = color ;
}
public void setX ( int x ) {
this . x = x ;
}
public void setY ( int y ) {
this . y = y ;
}
public void setRadius ( int radius ) {
this . radius = radius ;
}
@ Override
public void draw () {
Log . e ( "---" , "Circle: Draw() [Color : " + color
+ ", x : " + x + ", y :" + y + ", radius :" + radius );
}
}
3. Cree una fábrica para generar objetos de clases de entidad en función de la información proporcionada.
public class ShapeFactory {
private static final HashMap < String , Shape > circleMap = new HashMap < String , Shape >();
public static Shape getShape ( String color ) {
Shape shape = circleMap . get ( color );
if ( shape == null ) {
shape = new Circle ( color );
circleMap . put ( color , shape );
Log . e ( "getShape" , "Creating circle of color : " + color );
}
return shape ;
}
}
4. Utilice esta fábrica para obtener el objeto de la clase de entidad pasando información de color.
for ( int i = 0 ; i < 20 ; i ++) {
Circle circle = ( Circle ) ShapeFactory . getShape ( getRandomColor ());
circle . setX ( getRandomX ());
circle . setY ( getRandomY ());
circle . setRadius ( 100 );
circle . draw ();
}
Una clase representa la funcionalidad de otra clase. En el patrón proxy, creamos objetos con objetos existentes para proporcionar una interfaz funcional con el mundo exterior. Se puede entender que si no existe tal objeto en la memoria, se creará y, si existe, el objeto se devolverá directamente.
Tomando como ejemplo la obtención de imágenes del disco, hay tres pasos en total:
1. Cree una interfaz.
public interface Image {
void display ();
}
2. Cree una clase de entidad RealImage que implemente la interfaz. Clase de proxy correspondiente: ProxyImage.
public class RealImage implements Image {
private String fileName ;
public RealImage ( String fileName ) {
this . fileName = fileName ;
loadFromDisk ( fileName );
}
private void loadFromDisk ( String fileName ) {
Log . e ( "RealImage" , "loading " + fileName );
}
@ Override
public void display () {
Log . e ( "RealImage" , "Displaying " + fileName );
}
}
public class ProxyImage implements Image {
private String fileName ;
private RealImage realImage ;
public ProxyImage ( String fileName ) {
this . fileName = fileName ;
}
@ Override
public void display () {
if ( realImage == null ) {
realImage = new RealImage ( fileName );
}
realImage . display ();
}
}
3. Cuando se le solicite, utilice ProxyImage para obtener un objeto de la clase RealImage.
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
Bridge se utiliza para desacoplar la abstracción y la implementación de modo que las dos puedan cambiar de forma independiente. Este tipo de patrón de diseño es un patrón estructural que desacopla la abstracción y la implementación proporcionando una estructura puente entre ellas.
Tomando como ejemplo dibujar círculos de diferentes colores, la implementación se divide en cinco pasos:
1. Cree una interfaz de implementación de puente.
public interface DrawAPI {
void drawCircle ( int radius , int x , int y );
}
2. Cree una clase de implementación de puente de entidad que implemente la interfaz DrawAPI. Círculo rojo, círculo verde
public class RedCircle implements DrawAPI {
@ Override
public void drawCircle ( int radius , int x , int y ) {
Log . e ( "---" , "Drawing Circle[ color: red, radius: "
+ radius + ", x: " + x + ", " + y + "]" );
}
}
3. Utilice la interfaz DrawAPI para crear la clase abstracta Shape.
public abstract class Shape {
protected DrawAPI drawAPI ;
protected Shape ( DrawAPI drawAPI ) {
this . drawAPI = drawAPI ;
}
public abstract void draw ();
}
4. Cree una clase de entidad que implemente la interfaz Shape.
public class Circle extends Shape {
private int x , y , radius ;
protected Circle ( int x , int y , int radius , DrawAPI drawAPI ) {
super ( drawAPI );
this . x = x ;
this . y = y ;
this . radius = radius ;
}
@ Override
public void draw () {
drawAPI . drawCircle ( radius , x , y );
}
}
5. Utilice las clases Shape y DrawAPI para dibujar círculos de diferentes colores.
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
También llamado patrón parte-todo, se utiliza para tratar un grupo de objetos similares como un solo objeto. El modo de composición combina objetos según una estructura de árbol, que se utiliza para representar jerarquías parciales y totales. Este tipo de patrón de diseño es un patrón estructural que crea una estructura de árbol de grupos de objetos.
Tomemos como ejemplo la creación e impresión de una jerarquía de empleados, el ejemplo de unidad más pequeña:
1. Cree una clase de Empleado con una lista de objetos de Empleado.
public class Employee {
private String name ;
// 部门
private String dept ;
// 工资
private int salary ;
// 员工 list
private List < Employee > subordinates ;
public Employee ( String name , String dept , int salary ) {
this . name = name ;
this . dept = dept ;
this . salary = salary ;
this . subordinates = new ArrayList < Employee >();
}
public void add ( Employee e ) {
subordinates . add ( e );
}
public void remove ( Employee e ) {
subordinates . remove ( e );
}
public List < Employee > getSubordinates () {
return subordinates ;
}
@ Override
public String toString () {
return "Employee{" +
"name='" + name + ''' +
", dept='" + dept + ''' +
", salary=" + salary +
", subordinates=" + subordinates +
'}' ;
}
}
2. Utilice la clase Empleado para crear e imprimir la jerarquía de empleados.
final Employee ceo = new Employee ( "John" , "CEO" , 30000 );
Employee headSales = new Employee ( "Robert" , "Head sales" , 20000 );
Employee headMarketing = new Employee ( "Michel" , "Head Marketing" , 20000 );
Employee clerk1 = new Employee ( "Laura" , "Marketing" , 10000 );
Employee clerk2 = new Employee ( "Bob" , "Marketing" , 10000 );
Employee salesExecutive1 = new Employee ( "Richard" , "Sales" , 10000 );
Employee salesExecutive2 = new Employee ( "Rob" , "Sales" , 10000 );
ceo . add ( headSales );
ceo . add ( headMarketing );
headSales . add ( salesExecutive1 );
headSales . add ( salesExecutive2 );
headMarketing . add ( clerk1 );
headMarketing . add ( clerk2 );
Log . e ( "---" , ceo . toString ());
// 打印
/*
* Employee{name='John', dept='CEO', salary=30000,
* subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
* subordinates=[
* Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
* Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
* Employee{name='Michel', dept='Head Marketing', salary=20000,
* subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
* Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
*/
Patrón de diseño muy común en entornos de programación Java y .Net. Este patrón se utiliza para acceder secuencialmente a los elementos de un objeto de colección sin conocer la representación subyacente del objeto de colección. El patrón iterador es un patrón de comportamiento.
Tomando como ejemplo el uso de un iterador para imprimir nombres, hay tres pasos en total:
1. Cree una interfaz:
public interface Iterator {
public boolean hasNext ();
public Object next ();
}
public interface Container {
public Iterator getIterator ();
}
2. Cree una clase de entidad que implemente la interfaz Container. Esta clase tiene una clase interna NameIterator que implementa la interfaz Iterator.
public class NameRepository implements Container {
private String names [] = { "John" , "jingbin" , "youlookwhat" , "lookthis" };
@ Override
public Iterator getIterator () {
return new NameIterator ();
}
private class NameIterator implements Iterator {
int index ;
@ Override
public boolean hasNext () {
if ( index < names . length ) {
return true ;
}
return false ;
}
@ Override
public Object next () {
if ( hasNext ()) {
return names [ index ++];
}
return null ;
}
}
}
3. Utilice NameRepository para obtener el iterador e imprimir el nombre.
NameRepository nameRepository = new NameRepository ();
for ( Iterator iterator = nameRepository . getIterator (); iterator . hasNext (); ) {
String name = ( String ) iterator . next ();
Log . e ( "---" , name );
/*
* /---: John
* /---: jingbin
* /---: youlookwhat
* /---: lookthis
*/
}
Se utiliza para reducir la complejidad de la comunicación entre múltiples objetos y clases. Este patrón proporciona una clase intermediaria que normalmente maneja la comunicación entre diferentes clases y admite un acoplamiento flexible, lo que hace que el código sea más fácil de mantener. El modelo mediador es un modelo conductual.
Tomando como ejemplo una sala de chat pública, los pasos de ejemplo de unidad mínima son:
1. Cree una clase intermedia.
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2. Cree la clase de usuario.
public class User {
private String name ;
public User ( String name ) {
this . name = name ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public void sendMessage ( String message ) {
// 使用中介类
CharRoom . showMessage ( this , message );
}
}
3. Utilice el objeto Usuario para mostrar la comunicación entre ellos.
User jingbin = new User ( "jingbin" );
jingbin . sendMessage ( "Hi~ youlookwhat!" );
//---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
User jingbin = new User ( "youlookwhat" );
jingbin . sendMessage ( "Hi~ jingbin!" );
//---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
Guarde un determinado estado de un objeto para que pueda restaurarse en el momento adecuado. El modo memo es un modo de comportamiento.
Tomando como ejemplo el uso de memo, los pasos unitarios mínimos son:
1. Cree la clase Memento.
public class Memento {
private String state ;
public Memento ( String state ) {
this . state = state ;
}
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
}
2. Cree la clase Originador.
public class Originator {
private String state ;
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
public Memento setSateToMemento () {
return new Memento ( state );
}
public String getStateFromMemento ( Memento memento ) {
return memento . getState ();
}
}
3. Cree la clase CareTaker.
public class CareTaker {
private List < Memento > mementoList = new ArrayList < Memento >();
public void add ( Memento memento ) {
mementoList . add ( memento );
}
public Memento get ( int index ) {
return mementoList . get ( index );
}
}
4. Utilice objetos CareTaker y Originator.
// 管理者
CareTaker careTaker = new CareTaker ();
Originator originator = new Originator ();
originator . setState ( "State #1" );
originator . setState ( "State #2" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #3" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #4" );
Log . e ( "---" , "Current State: " + originator . getState ());
// 得到保存的状态
String fromMemento1 = originator . getStateFromMemento ( careTaker . get ( 0 ));
Log . e ( "---" , "First Saved State: " + fromMemento1 );
String fromMemento2 = originator . getStateFromMemento ( careTaker . get ( 1 ));
Log . e ( "---" , "Second Saved State: " + fromMemento2 );
/*
* /---: Current State: State #4
* /---: First Saved State: State #2
* /---: Second Saved State: State #3
*/
Proporciona una forma de evaluar la gramática o expresiones de una lengua y es un patrón de comportamiento. Este patrón implementa una interfaz de expresión que interpreta un contexto específico. Este modo se utiliza en análisis de SQL, motores de procesamiento de símbolos, etc.
Tome como ejemplo una oración explicativa, los pasos unitarios mínimos:
1. Cree una expresión de interfaz de expresión.
public interface Expression {
public boolean interpreter ( String content );
}
2. Cree una clase de entidad que implemente la interfaz anterior. TerminalExpresión, OExpresión, YExpresión.
public class TerminalExpression implements Expression {
private String data ;
public TerminalExpression ( String data ) {
this . data = data ;
}
@ Override
public boolean interpreter ( String content ) {
// 是包含判断
return content . contains ( data );
}
}
public class OrExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public OrExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) || expression2 . interpreter ( content );
}
}
public class AndExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public AndExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) && expression2 . interpreter ( content );
}
}
3. Utilice la clase Expresión para crear reglas y analizarlas.
/**
* 规则:jingbin 和 youlookwhat 是男性
*/
public static Expression getMaleExpression () {
TerminalExpression jingbin = new TerminalExpression ( "jingbin" );
TerminalExpression youlookwhat = new TerminalExpression ( "youlookwhat" );
return new OrExpression ( jingbin , youlookwhat );
}
/**
* 规则:Julie 是一个已婚的女性
*/
public static Expression getMarriedWomanExpression () {
TerminalExpression julie = new TerminalExpression ( "Julie" );
TerminalExpression married = new TerminalExpression ( "Married" );
return new AndExpression ( julie , married );
}
Expression maleExpression = getMaleExpression ();
// jingbin is male: true
Log . e ( "---" , "jingbin is male: " + maleExpression . interpreter ( "jingbin" ));
Expression womanExpression = getMarriedWomanExpression ();
// Julie is married woman: true
Log . e ( "---" , "Julie is married woman: " + womanExpression . interpreter ( "Married Julie" ));
El patrón de cadena de responsabilidad crea una cadena de objetos destinatarios para una solicitud. Este patrón desacopla al remitente y al receptor de la solicitud según el tipo de solicitud. Este tipo de patrón de diseño es un patrón de comportamiento. En este patrón, normalmente cada receptor contiene una referencia a otro receptor. Si un objeto no puede manejar la solicitud, pasa la misma solicitud al siguiente destinatario, y así sucesivamente.
Tomando como ejemplo la impresión de registros en Android Studio, los pasos unitarios mínimos son:
1. Cree una clase de registrador abstracto AbstractLogger.
public abstract class AbstractLogger {
public static int INFO = 1 ;
public static int DEBUG = 2 ;
public static int ERROR = 3 ;
protected int level ;
// 责任链中的下一个元素
protected AbstractLogger nextLogger ;
public void setNextLogger ( AbstractLogger nextLogger ) {
this . nextLogger = nextLogger ;
}
public void logMessage ( int level , String message ) {
if ( this . level <= level ) {
write ( message );
}
// 递归效果,不断调用下一级 logMessage
if ( nextLogger != null ) {
nextLogger . logMessage ( level , message );
}
}
protected abstract void write ( String message );
}
2. Cree una clase de entidad que extienda la clase de registrador.
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Standard Console::Logger " + message );
}
}
public class FileLogger extends AbstractLogger {
public FileLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "File::Logger " + message );
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Error Console::Logger " + message );
}
}
3. Cree diferentes tipos de registradores. Deles diferentes niveles de error y dentro de cada registrador configure el siguiente registrador. El siguiente registrador de cada registrador representa parte de la cadena.
public static AbstractLogger getChainOfLoggers () {
ErrorLogger errorLogger = new ErrorLogger ( AbstractLogger . ERROR );
FileLogger fileLogger = new FileLogger ( AbstractLogger . DEBUG );
ConsoleLogger consoleLogger = new ConsoleLogger ( AbstractLogger . INFO );
errorLogger . setNextLogger ( fileLogger );
fileLogger . setNextLogger ( consoleLogger );
return errorLogger ;
}
AbstractLogger logger = getChainOfLoggers ();
// ---: Standard Console::Logger this is an information.
logger . logMessage ( AbstractLogger . INFO , "this is an information." );
// ---: File::Logger this is a debug level information.
// ---: Standard Console::Logger this is a debug level information.
logger . logMessage ( AbstractLogger . DEBUG , "this is a debug level information." );
// ---: Error Console::Logger this is a error level information.
// ---: File::Logger this is a error level information.
// ---: Standard Console::Logger this is a error level information.
logger . logMessage ( AbstractLogger . ERROR , "this is a error level information." );
En el patrón de visitante, utilizamos una clase de visitante, que cambia el algoritmo de ejecución de la clase de elemento. De esta forma, el algoritmo de ejecución del elemento puede cambiar a medida que cambia el visitante. Este tipo de patrón de diseño es un patrón de comportamiento. Según el esquema, el objeto elemento ha aceptado un objeto visitante para que el objeto visitante pueda manejar operaciones en el objeto elemento.
Tomando como ejemplo los componentes de una computadora con pantalla, se implementa principalmente en cinco pasos:
1. Defina una interfaz que represente el elemento.
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2. Cree una clase de entidad que extienda la clase anterior. Teclado,Monitor,Ratón,Ordenador
public class Computer implements ComputerPart {
private ComputerPart [] parts ;
public Computer () {
this . parts = new ComputerPart []{ new Mouse (), new Keyboard (), new Monitor ()};
}
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
for ( ComputerPart part : parts ) {
part . accept ( computerPartVisitor );
}
computerPartVisitor . visit ( this );
}
}
public class Mouse implements ComputerPart {
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
computerPartVisitor . visit ( this );
}
}
3. Defina una interfaz que represente a los visitantes.
public interface ComputerPartVisitor {
public void visit ( Computer computer );
public void visit ( Mouse mouse );
public void visit ( Keyboard keyboard );
public void visit ( Monitor monitor );
}
4. Cree visitantes de entidades que implementen las clases anteriores.
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@ Override
public void visit ( Computer computer ) {
Log . e ( "---" , "Displaying Computer." );
}
@ Override
public void visit ( Mouse mouse ) {
Log . e ( "---" , "Displaying Mouse." );
}
@ Override
public void visit ( Keyboard keyboard ) {
Log . e ( "---" , "Displaying Keyboard." );
}
@ Override
public void visit ( Monitor monitor ) {
Log . e ( "---" , "Displaying Monitor." );
}
}
5. Utilice ComputerPartDisplayVisitor para mostrar los componentes de Computer.
ComputerPart computer = new Computer ();
computer . accept ( new ComputerPartDisplayVisitor ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/