6
votes

Design orienté objet?

J'essaie d'apprendre la programmation orientée objet, mais j'ai du mal à surmonter mon arrière-plan de programmation structuré (principalement C, mais beaucoup d'autres au fil du temps). Je pensais écrire un programme de registre de contrôle simple comme un exercice. Je mets quelque chose ensemble assez rapidement (Python est une grande langue), avec mes données dans certaines variables globales et avec un tas de fonctions. Je ne peux pas comprendre si cette conception peut être améliorée en créant un certain nombre de classes pour encapsuler certaines des données et des fonctions et, le cas échéant, comment changer la conception.

Mes données sont fondamentalement une liste de comptes ["Vérification", "Sauvegarde", "AMEX"], une liste de catégories ["Food", "Shelter", "Transport"] et des listes de DICTS qui représentent des transactions [ {'DATE': XYZ, 'CAT': XYZ, «Montant»: XYZ, 'Description': XZY]. Chaque compte a une liste associée de dict.

J'ai alors des fonctions au niveau du compte (Create-Acct (), Display-ACCTS (), etc.) et le niveau de transaction (entrées-entrées-in-compte (), entrée-A-transaction ( ), éditeur-transaction (), entrées d'affichage - entre-dates (), etc.)

L'utilisateur voit une liste de comptes, puis peut choisir un compte et voir les transactions sous-jacentes, avec la possibilité d'ajouter, de supprimer, de modifier, etc. les comptes et les transactions.

Je connais actuellement tout dans une grande classe, de sorte que je puisse utiliser Self.Variaable, plutôt que des globaux explicites.

En bref, j'essaie de déterminer si réorganiser cela dans certaines classes serait utile et, dans l'affirmative, comment concevoir ces classes. J'ai lu des livres de POO (dernier processus de pensée orienté objet). J'aime penser que mon design existant est lisible et ne se répète pas.

Toutes les suggestions seraient appréciées.


2 commentaires

Qu'avez-vous lu? Quels livres de design OO avez-vous lu?


@ S.Lott, en plus de celui que j'ai mentionné, l'apprêt d'objet, efficace C ++, bande de 4, d'autres, je ne peux pas me rappeler immédiatement. Je viens de commencer votre livre en ligne. J'ai essayé les premiers livres de la tête, mais je ne les ai pas aimés


5 Réponses :


5
votes

Pas une réponse directe à votre question mais O'Reilly's Tête Une première analyse et design orientées objet est un excellent endroit pour commencer.

suivi de Premier modèle de la tête


1 commentaires

Je me rends compte qu'ils sont très populaires, mais je ne pouvais pas entrer dans ces livres



3
votes

"Mes données sont essentiellement une liste de comptes"

compte est une classe.

"dicts qui représentent des transactions"

transaction semble être une classe. Vous avez choisi de représenter cela comme un dict.

C'est votre premier passage à OO Design. Concentrez-vous sur les responsabilités et les collaborateurs.

Vous avez au moins deux classes d'objets.


9 commentaires

Mais ne laissez pas les détails de la mise en œuvre (tels que représentés par un dict) dictent comment vous modélisez le problème.


Les comptes auraient des méthodes et des transactions liées au compte des méthodes de transaction, chacune ayant des méthodes permettant de transmettre des données pertinentes à l'autre?


@RDP: correct. C'est le problème de la collaboration.


Comment programmer la collaboration? Pour le moment, le programme principal crée une classe d'applications qui inclut toutes les méthodes et les appelle en fonction de la saisie de l'utilisateur. Dois-je mettre en place la classe d'application pour créer des comptes et des transactions les cas, le cas échéant et médiane les communications entre elles?


@RDP: correct. Un dict est une classe. Vous remplacez des dicts muetts avec des cours qui ont des méthodes concentrées sur les membres de la dicte.


@ S.Lott - J'ai un bloc mental sur la mise en œuvre et je manque probablement quelque chose d'évident. Si je suis dans un cadre d'interface graphique, j'ai une classe d'applications principale qui lie les actions utilisateur (telles que les clics ou les touches) pour rappeler des fonctions (ou répond aux signaux en appelant les machines à sous). En d'autres termes, chaque action d'utilisateur appelle une méthode / la fonction. Dans mon exemple, l'utilisateur commence par une liste de comptes (qui s'affiche à l'aide de certains éléments GUI), puis clique sur le compte et obtient une liste des transactions. Comment utiliser une classe de compte ou une classe de transaction dans ce contexte?


@RDP: Remplacez d'abord des objets Dictionnaire Dumb avec des objets plus intelligents en fonction des définitions de classe que vous avez écrites. Cela n'a rien à voir avec les racines de l'interface graphique. Une application d'interface graphique présente plusieurs parties: un modèle sous-jacent, ainsi que la présentation de l'interface graphique (ou la vue), ainsi que le contrôle qui tricoter des choses ensemble, répond aux rappels. Tous ces éléments impliquent des objets. Votre modèle ne doit pas être juste des dictionnaires muettes.


@ S.Lott, juste pour clarifier, que diriez-vous: Créer une classe MyData, qui détient et peut modifier le jeu de données, puis le reste du programme interagit avec MyData plutôt que de traiter directement les données?


@RDP: Vous manquez une partie du point. Votre classe MyData myData pour une base de données appropriée. Mais les comptes et les transactions sont des classes distinctes et doivent être définies de cette façon.



1
votes

Il existe de nombreux «mentacés» que vous pourriez adopter pour aider dans le processus de conception (dont certains surviennent vers OO et certains qui ne le font pas). Je pense qu'il est souvent préférable de commencer par des questions plutôt que de réponses (c'est-à-dire plutôt que de dire: «Comment puis-je appliquer héritage à cela» vous devez demander comment ce système pourrait s'attendre à changer au fil du temps).

Voici quelques questions à répondre que cela pourrait vous indiquer vers Principes de conception:

  • Les autres vont-ils utiliser cette API? Sont-ils susceptibles de le casser? ( Info cache )
  • Dois-je le déployer dans de nombreuses machines? ( Gestion de l'État, Gestion du cycle de vie )
  • Dois-je interopérer avec d'autres systèmes, des e-mails, des langues? ( Abstraction et Normes )
  • Quelles sont mes contraintes de performance? ( Gestion de l'État, Gestion du cycle de vie )
  • Quel type d'environnement de sécurité réside dans ce composant? ( Abstraction, Cachée d'informations, Interopérabilité )
  • Comment construirais-je mes objets, en supposant que j'en utilisais? ( Configuration, inversion du contrôle, découplage de l'objet, caché des détails de la mise en œuvre )

    Ce ne sont pas des réponses directes à votre question, mais elles pourraient vous mettre dans le bon état d'esprit pour y répondre vous-même. :)


4 commentaires

+1 pour souligner que son en arrière pour embrasser des solutions puis commencer à chercher des problèmes à résoudre avec eux.


Des mentalités utiles, d'autant plus que ma première question étaient de savoir si les classes seraient utiles, plutôt que de la procédure d'OUP.


RDP, désolé si je vous ai donné une infraction, je n'impliquais pas que vous traitait OOP en tant que solution à la recherche d'un problème, mais cela peut être un problème pour ceux qui viennent d'autres domaines. J'ai toujours trouvé le domaine OO entièrement intuitif et j'ai précisément que lorsque j'ai commencé à embrasser le domaine fonctionnel avec l'avènement de Linq, etc. en C #. Une chose que je remarque sur Python (disons) est que la syntaxe fonctionnelle est beaucoup moins maladroite que la syntaxe OO. Peut-être qu'une mise en œuvre fonctionnelle est susceptible d'être plus propre qu'une OO One en Python?


@Andrew, désolé si j'ai semblé offensé. Une partie de ma question était de savoir si OO était utile et que vous avez donné des suggestions très utiles pour envisager si OO serait utile.



7
votes

Vous n'avez pas à jeter la programmation structurée pour effectuer une programmation orientée objet. Le code est toujours structuré, il appartient simplement aux objets plutôt que d'être séparés d'eux.

Dans la programmation classique, le code est la force motrice qui fonctionne sur des données, ce qui conduit à une dichotomie (et la possibilité que le code puisse fonctionner sur les données mauvaises ).

dans OO, les données et le code sont inextricablement enlacés - un objet contient à la fois des données et le code à utiliser sur ces données (bien que techniquement, le code (et parfois certaines données) appartiennent à la classe plutôt qu'à un objet individuel). Tout code client qui veut utiliser ces objets doit ne le faire que en utilisant le code dans cet objet. Cela empêche le problème de décalage de code / de données.

Pour un système de comptabilité, je l'aborderais comme suit:

  1. Les objets de bas niveau sont des comptes et des catégories (en réalité, il n'y a pas de différence entre ceux-ci, il s'agit d'une fausse séparation exacerbée par Quicken et al à des éléments de bilan distincts de P & L - Je vais les faire référence à titre de comptes seul). Un objet de compte comprend (par exemple) un code de compte, un nom et un solde de départ, bien que dans les systèmes comptables que j'ai travaillé, le solde de départ est toujours zéro - j'ai toujours utilisé une transaction "de démarrage" pour définir les balanaces initialement .
  2. Les transactions sont un objet équilibré comprenant un groupe de comptes / catégories avec des mouvements associés (changements de valeur en dollars). Par équilibre, je veux dire qu'ils doivent résumer à zéro (ceci est le creux de la comptabilité de double entrée). Cela signifie qu'il s'agit d'une date, d'une description et d'une matrice ou d'un vecteur d'éléments, chacun contenant un code de compte et une valeur.
  3. L'objet de la comptabilité globale "objet" (le grand livre) est alors simplement la liste de tous les comptes et transactions.

    Gardez à l'esprit qu'il s'agit de «back-end» du système (le modèle de données). J'espère avoir des classes séparées pour la visualisation des données (la vue) qui vous permettra de le modifier facilement, en fonction des préférences de l'utilisateur. Par exemple, vous souhaiterez peut-être le grand livre, juste le bilan ou uniquement le P & L. Ou vous pouvez vouloir que des gammes de date différentes.

    Une chose que je stresse pour faire un bon système de comptabilité. Vous les avez besoin de penser comme un comptable. Je veux dire perdre la différence artificielle entre les "comptes" et les "catégories" car il rendra votre système beaucoup plus propre (vous devez pouvoir disposer de transactions entre deux comptes de classe d'actifs (tels qu'un virement bancaire) et ce gagné 'T Travailler si chaque transaction nécessite une "catégorie". Le modèle de données doit refléter les données, non la vue.

    La seule difficulté Il se souvient que des comptes de classe d'actifs ont le signe opposé à partir desquels vous vous attendez (des valeurs négatives pour votre argent à la banque, vous avez de l'argent à la banque et votre très élevé positif Prêt de valeur pour cette société de sport La voiture est une dette , par exemple). Cela rendra parfaitement l'aspect de la double entrée, mais vous devez vous rappeler d'inverser les signes de comptes de classe d'actifs (actifs, passifs et capitaux propres) lors de l'affichage ou de l'impression du bilan.


7 commentaires

w.r.t. "La possibilité que le code puisse fonctionner sur les mauvaises données": Savez-vous ce qu'est un système de type pour, non?


Donc, @ Mad70, dans votre code C, Tous Vos types seraient entièrement Typefed et vous n'utiliseriez pas d'entiers ou de flotteurs nulle part, oui? Parce que, sinon, il est est une possibilité que vous transmettez les mauvaises données sur une fonction.


Je ne programme pas en C, mais bien sûr, j'essaie d'utiliser un système de type de programmation (PL) dans toute sa mesure, qu'il s'agisse d'un objet orienté objet, procédural, fonctionnel, logique (ou basé sur le paradigme) pl. Ce type de sécurité est accordé par un système de type non par le fait qu'un PL est OO ou non.


Ne pas parler couramment C, je n'ai pas réalisé que même votre question rhétorique se réfère à un faux fait: Typedef Introduisez un simple synonyme de type, équivalent à son type de base pour le vérificateur de type, de sorte que l'inutile une mesure de sécurité. Avec d'autres pls avec un système de type nominal décent, ce n'est pas le cas: un nouvel identifiant de type introduit un nouveau type incompatible avec un type de type / structure de base.


Quoi qu'il en soit, le vérificateur de type vous empêche de planter un programme tout en appelant une méthode inexistante ou en passant un paramètre du type incorrect à une méthode. Sans un vérificateur de type Aucun message au moment de la compilation (pour les pls de type statique) ou l'exécution (pour les pls dactylographiés): le programme se bloque simplement ou commencez à se comporter de manière étrange.


N'est pas correct que "dans OO, les données sont roi". Structurellement, OO ne fait pas la distinction entre l'état et le comportement, traite des atomes des deux types uniformément comme des "caractéristiques". OO La conception est le processus de minimisation de la dépendance globale entre toutes les caractéristiques de l'état et du comportement en tremblant ces caractéristiques dans les classes.


Bon point, @doug, je suppose que j'aurais dû dire "objet" au lieu de "données". Quoi qu'il en soit, je l'ai réparé selon votre suggestion.



-1
votes

Plutôt que d'utiliser des dicts pour représenter vos transactions, un meilleur conteneur serait nommé au module de collections. Un nomméTuple est une sous-classe de tuple qui vous permet de faire référence à ses articles par nom, ainsi que le numéro d'index.

Puisque vous pouvez avoir des milliers de transactions dans vos listes de journaux, il est payant de garder ces articles comme petit et léger le plus possible pour que le traitement, le tri, la recherche, etc. soit aussi rapide et réactif que possible. Un dict est un objet assez lourd de poids comparé à un NamedTuple qui ne prend plus de mémoire qu'un tuple ordinaire. Un nomméTuple a également l'avantage supplémentaire de garder ses articles dans l'ordre, contrairement à un dict. xxx

Vous voyez donc que cela fait presque 9 fois l'enregistrement de la mémoire pour une transaction de huit articles. J'utilise Python 3.1, votre militant peut donc varier.


1 commentaires

Nomples Nomples a commencé en 2.6. En tout état de cause, il s'agit davantage d'une question de mise en œuvre de bas niveau qu'un problème de conception. Utile à retenir.