Cómo evitar ... clases de ayudante o ... gerente

9

Tengo bastantes clases de ayudantes en mi proyecto. He leído que esto es algo malo, pero sospecho que "Helper" es el sufijo incorrecto para ellos. Daré un ejemplo.

Primero, tengo una Userclase. Necesito un método GetSuggestedFriends()para un usuario. Quiero mantener la lógica para determinar la lista de amigos sugeridos fuera de la Userclase, para que no se hinche. En este momento, tengo un FriendshipHelperque recibe un Useren su constructor. Contiene la lógica para obtener amigos sugeridos, y ahora puedo llamar myUser.FriendshipHelper.GetSuggestedFriends().

Originalmente FriendshipHelpertenía métodos estáticos solamente, y Userse pasó un objeto a cada uno. Si escribiera la clase desde cero ahora, tal vez lo llamaría FriendshipManager, también hace cosas como agregar y eliminar amigos.

Sin ...Managerembargo, también he leído que las clases son malas. ¿Cómo debería llamar a esta clase? ¿O es este "código incorrecto"? ¿Dónde debería vivir la lógica para obtener amigos sugeridos, amigos actuales y agregar y eliminar amigos? ¿Seguramente no todos en una Userclase gigante ?

usuario1002973
fuente
¿Dónde vive este código? ¿Es un servicio? ¿Accede a un almacén de datos? ¿Es la interfaz de usuario para hacer estas cosas de amigos?
Telastyn
3
Una vez que haya eliminado todos los métodos estáticos y haya encontrado un hogar real en su diseño de OOP, estas clases realmente no son clases auxiliares, así que no dude en cambiar el nombre. No hay nada malo con un FriendshipManager si necesita administrar las amistades en su proyecto.
JeffO
¿Qué tiene de malo Facebook?
toniedzwiedz

Respuestas:

10

Cómo evitar ... clases de ayudante o ... gerente «

En general: por buen diseño

Primero, tengo una clase de usuario. Necesito un método GetSuggestedFriends () para un usuario.

Si. A user tiene una relación con otro users. Y la relación podría expresarse como un método user, por ejemplo user.isFriend(user2). Esta es la responsabilidad del objeto user. Además de eso, le pides ayuda a otro objeto para encontrar otros amigos . Delegas la responsabilidad de encontrar amigos a otro objeto y eso está bastante bien .

En este momento, tengo un FriendshipHelper que recibe un usuario en su constructor. Contiene la lógica para obtener amigos sugeridos, y ahora puedo llamar a myUser.FriendshipHelper.GetSuggestedFriends ()

Eso no es per se malo, pero tiene una desventaja: inicializar el "Helper" con uno userlimita las posibilidades a ese user.

Lo que necesita es un objeto , que ayuda a encontrar amigos para cualquier usuario. Por lo tanto, un método genérico tendría sentido: userMatcher.findFriendsFor(user)que a cambio ofrece una colección de posibles amigos ( user).

Si estuviera escribiendo la clase desde cero ahora, tal vez lo llamaría FriendshipManager

Su problema no es escribir "clases auxiliares", es encontrar los nombres correctos . ;)

También hace cosas como agregar y eliminar amigos.

Ese es un diseño incorrecto . Tómese por ejemplo: ¿su mamá agrega amigos a su vida o los agrega usted mismo?

Por supuesto, la colección de amigos es una propiedad en usersí misma y también lo es el método user.addFriend(user)ouser.removeFriend(user)

¿Cómo debería llamar a esta clase?

Como se dijo antes: solo tiene un problema de nomenclatura y sus "ayudantes" están bien . Pero tienes que pensar más cuidadosamente sobre las responsabilidades de cada objeto.

¿Dónde debería vivir la lógica para obtener amigos sugeridos, amigos actuales y agregar y eliminar amigos? Seguramente no todo en una clase de usuario gigante

No. Estos son dos trabajos para los que necesita un objeto separado , como en la vida real donde tiene personas y una agencia de citas .

Thomas Junk
fuente
3
Gran explicación, pero claramente nunca conociste a mi madre. : '(
Matt
1
@ HEATH3N Espero que eso no influya en sus capacidades de modelado de software.
Thomas Junk
3

Sugeriría que tenga una FriendshipServiceclase que tenga un GetSuggestedFriends(User)método (no estático) . Evite los métodos estáticos, ya que no puede implementar una interfaz que dificulte la prueba. Evite agregar el objeto de usuario al constructor, ya que es posible que desee ampliar su FriendshipService con métodos no relacionados específicamente con un solo usuario. (Por ejemplo, es posible que desee sugerir amigos a un conjunto de usuarios o sugerir amigos según otra cosa)

Lo más probable es que un usuario no sea consciente del FriendshipService(debido al Patrón de responsabilidad única)

Bjorn
fuente
77
Cambiar el sufijo de "Ayudante" a "Servicio" no hace que sea más fácil hacerse una idea de la responsabilidad de la clase por su nombre, que creo que es el meollo de la pregunta.
Mike Partridge
Bueno, el nombre en sí mismo puede no decir mucho, pero yo diría que usar el sufijo "Servicio" es una forma más estandarizada de comunicar que la clase realiza algún tipo de lógica avanzada. Las clases "auxiliares" (al menos según mi experiencia) suelen estar más relacionadas con tareas muy simples, como el formato simple y los pequeños métodos estáticos. Espero que pueda reemplazar una interfaz de "Servicio" con diferentes implementaciones. Además, hay muchas preguntas aquí, no solo los nombres.
Bjorn
Convenido. Los tres "Ayudante", "Administrador" y "Servicio" son formas en que agrupamos métodos para evitar toneladas de clases súper específicas con un solo método, pero "Servicio" tiene un poco más de significado, como usted describió. Agregaría que implica que la clase es parte de la interfaz de la capa de servicio, lo que ayuda a simplificar el acceso a la lógica de negocios (que puede estar compuesta por muchas más clases específicas) para una clase de dominio determinada. Si la lógica de la sugerencia debe estar en una clase separada de la lógica de agregar / quitar depende de cuán compleja sea la implementación de la lógica de la sugerencia.
Mike Partridge
Cuando nombramos las clases ThingManager o ThingService, abrimos la puerta para crear clases que crecen fuera de control. Debido a que el nombre no indica claramente nada específico que pertenezca a la clase, tampoco excluye nada. Necesito un nuevo método que trate con Thing. ¿A dónde va? Idk, ponlo en ThingManager con todos los otros métodos.
Scott Hannen