Best approach to separate Model, View, and Control

2019-03-19 18:38发布

问题:

I'm thinking about the best approach to separate Model View and Controller—for Java and using Eclipse, if it makes any difference.

I used to separate each type's MVC inside its own package, but I'm start to think that this is not the best approach:

  • com.company.client (controler)
  • com.company.client.model
  • com.company.client.view

  • com.company.another (controler)

  • com.company.another.model
  • com.company.another.view

  • com.company.yetAnother (controler)

  • com.company.yetAnother.model
  • com.company.yetAnother.view

(assume a lot of different packages, each one with its own view and model)

I thought about use:

  • com.company.client
  • com.company.another
  • com.company.yetAnother

  • com.company.model.client

  • com.company.model.another
  • com.company.model.yetAnother

  • com.company.view.client

  • com.company.view.another
  • com.company.view.yetAnother

I even thought about putting the controller, model, and view in different projects. Maybe it would be even more modular, and I would be more sure that the view is not using the controller, for example (as the controller project would include the view, but not the reverse).

So what is the best approach to separate M, V, and C?

(consider web and desktop apps, not just web)

回答1:

The Graal Quest! You have two dimensional matrix with vertical (MVC) AND horizontal (business rules) layers...

  • I haven't found a strict answer
  • Your first approach looks good because modular oriented (unintended maybe)
  • For a small app your second though maybe acceptable

For me response is a word: dependencies
Keep searching in "package design/strategy" ; "Granularity"

Some reading

  • http://techdistrict.kirkk.com/2009/08/05/modularity-patterns/
  • http://techdistrict.kirkk.com/2010/04/22/granularity-architectures-nemesis/

I strongly recommand this one:

  • http://www.jgoodies.com/articles/patterns-and-binding-old.pdf

GOOD LUCK!



回答2:

Assuming you have to deal with a non trivial project, I think your problem have two aspects to be jointly considered for setting up architecture and code quality:

  • naming
  • modularization

For naming I try to have the highest cohesion in every namespace and to follow the Common Closure Principle and Common Reuse Principle.

For modularization I try to use a module for every architectural main issue of the project and name conveniently its packages.

MVC is a presentation module pattern which aims to separate how the presentation module controls flow, what models of data it is based on and which is the view related logic.

In my java IDE (e.g. Eclipse) I use a project per module, so web module will be a project and desktop module will be another project. In a web project, for example I have a common prefix, such as:

com.mycompany.app.web

and in it I have a .controllers (or actions) descendant, a .models descendant and so on.

com.mycompany.app.web.models
com.mycompany.app.web.actions

If I use a database I rely on a DAO module, another project. DAO module doesn't have a presentation so it doesn't have an MVC approach. It persists Domain objects, so maybe it relies on a Domain module. In these modules I use prefixes like the following:

com.mycompany.app.domain
com.mycompany.app.dao

I try to not confuse Model in MVC with application Domain; they aren't the same thing.

Another common mistake is to confuse Controller with Business Logic; business logic should be placed into a module and shared across presentation modules, the controller in a namespace of the presentation module (web or desktop).

A Model (in MVC, a view model) is an object used by a view to show something to the user: it may contains one, a combination or a collection of Domain objects. The Controller uses available modules (DAO, etc.) to build a view Model and then passes it to a View.

View then can rely only on its Model (only one, expressly created by the controller) and ask for models only to the controllers (the only able to build models). View, especially for web presentations, often is coded in a blend of languages, so part of the code could remain outside of naming conventions.



回答3:

Are you only concerned with "separating" the Model, View and Controller as far as naming and packages go? This seems to be all you are asking about.

I tend to lay out my packages as such:

  • com.company.app.domain - Domain model classes for the application, simply Java beans (getters and setters only, very little if any logic). This is used as "the model" throughout the application and used by every layer of my application.
  • com.company.app.service - Service level classes of the application, containing business logic.
  • com.company.app.web.controllers - Controller classes for my webapp. Other web-specific classes are put in various other subpackages of web.
  • com.company.app.dao - DAO interfaces for accessing the domain model classes - i.e. to retrieve a User from the database, etc.

Within each of these, packages are sometimes broken down by area of the application or into smaller groups based on functionality, whatever seems appropriate.



回答4:

I think it is also important to consider how you would like to ultimately utilize the fact you have broken out separate modules in your code base. I.E. What type of utility other than basic code quality are you looking at exploiting based on your packaging scheme.

Most of the apps i work on follow the following packaging structure: *.domain, *.service.subservice, *.dao, *.web.controllers. This works out nicely for tracking cyclic dependencies in the code base and/or dependencies which flow the wrong way ( controller hitting the dao without the indirection of a service ). It also provides a very simple packaging structure which is useful and non burdensome.

However, this breaks down when looking at automated dependency impact assessments. I currently use DependencyFinder with a bit of custom code to compare two jar files before QA. DependencyFinder will pull all modified methods and their associated first level dependencies. Custom code has to kick in to map the modified methods/classes to business functions and spits out a graphviz grammar file for rendering a business function based change-set, dependency graph for QA. We currently attempt to the use the results of the tool for smart regression test planning particularly for production defects which are moving to production without a full multi-week regression test.

The directory structure you propose will make the second case much easier. However, i also found that most of my development team does not really care dependencies at all, so the utility of the auto-dependency checker may vary :)



回答5:

Here is an example using a Layered Architecture design with three layers (application, domain, ui):

In the model-view-controller (MVC) the Model would be in a lower layer, such as com.company.myapp.domain. All other layers can access the Model. Then the View and the Controller would be in com.company.myapp.ui. That means the Controller class is always in the same layer as View. Don't confuse the MVC-Controller with other controller classes that provide application logic and reside in the application layer. For example a SalesController in com.company.myapp.application, which provides system operations to handle sales.

You can now imagine the SalesController changes some data in your model (updates a Sale) and the model then informs the MVC-Controller which updates the View.

Note: All Models are in the domain layer. All Views and MVC Controllers are in the ui layer. Business Logic Controllers are in the application layer. You can of course subdivide these three layers further if you have many classes with different concerns.

I hope this helps.



回答6:

Think about how you develop. Do you develop per Controller/ Model/ View? Or do you develop per module. Chances are you develop on a module and not on an MVC layer. So therefore I think there lies your answer. Try to keep your package names as close to the modules your system represent (which you are already doing I suppose). No need to show you architectural choices in you package names.

Showing module names and domain issues in you package create a maintainable and consistent codebase.