Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am learning design pattern from Head first book and I understood most of them. But when I try to apply in real world, it becomes more difficult. In every example, it has created lot of sub classes. But do we really create so much classes in real time projects?
E.g. Consider an example of Bank Account
Approach 1:
Account {
String name;
double balance;
operation1() {
}
}
SavingAccount extends Account {
// some extra fields and methods related to saving account
operation1() {
}
}
CurrentAccount extends Account {
// Some extra fields and methods related to current account.
operation1() {
}
}
When I map these classes with database, using Hibernate using one of the inheritance strategy, e.g. table per sub class, I will end up with three tables. Account, Saving_account and Current_account.
Advantage: I can call operation1() depending on the type of object using polymorphism.
Disadvantage: more tables and classes. If project is more complex and big, It will end up with thousands of classes.
Approach 2:
Account {
string name;
double balance;
string type;
operation1() {
}
}
I need only 1 table for this approach called Account. And "type" field will identify the type of the account.
Advantage: Only 1 table and class.
Disadvantage: I will lose Object oriented world and every place I have to put the condition as below.
if (type == saving) {
// do this;
} else if (type == current) {
// do that;
}
As per theory, approach 1 is correct and best. But currently in my project, approach 2 is used. My project is not banking. I took it as an example for the simplicity.
I know this is very basic question. But due to my current project implementation, I could not stop myself asking this question.
EDIT: maintainability of approach 1 is more better than approach 2.
Design patterns like inheritance are difficult to describe in terms of their importance, because it takes a very large project to realize the power of it. Usually examples end up with stuff like:
class A {
}
class B extends A {
}
class C extends B {
}
class D extends A {
}
And then you get a lot of not so real life questions like which method foo() really refers to when it's implemented four separate times.
The motivation for using inheritance is to group similar types of things together in a class. A basic example is if you want to have a bunch of different objects all in a list together. This isn't possible if they're all different types, but if they're in an inheritance hierarchy, you can group them all together.
For your example, you can put every Account object into a single list, no matter which subclass the objects are really in.
List<Account> list = new ArrayList<Account> ();
list.add(new Account());
list.add(new SavingsAccount());
list.add(new CurrentAccount());
Say you want to process every thing in that list. If you have one common method, you can use polymorphism to make each Account do its own specific action:
for(Account a : list) {
a.operation1();
}
Much simpler than having a separate list for each type of object, no? And then if you want to make more types of accounts, if you extend the base Account class, you don't have to add new lists and new loops to your code. Everything can remain as is.
Using inheritance also helps to use code that other people have written. If you want to add something to a class that someone else has written, you can include it in a package and then extend it with one of your own classes. That way you don't have to do a lot of copy and pasting and navigating through the other class's source code. You also can extend another class even if you only have its .class file, rather than the source code in a .java file.
So the power of inheritance depends on how you use it. In a small example, it doesn't really make sense. But the bigger the project, the more it makes sense.
Both approaches are valid as you just mentioned and the pros and cons you explained are also valid.
But for example you if you are Giving this Accounting package (compiled jar) as a library to be extended by other people, the approach 1 is ideal because;
You don't need to modify any source code of Account, just extend it and then implement your own version. Ex:- FixedDepositAccount
Won't break your Account code.
No need of Testing again for Account.operation1()
But if you are willing to share the source code and willing to do above mentioned steps then it is best to use method 2.
In Java we can have String type; (not string type;), but even better would be an Enum type (that way we could have add a Money Market Account or a Platinum Preferred Savings Account, possibly without re-implementing the caller code). Something like,
enum AccountType {
CHECKING(0.005), SAVINGS(0.01), MMA(0.02);
final double rate;
private AccountType(double rate) {
this.rate = rate;
}
public double getRate() {
return this.rate;
}
}
And with an AccountType you can safely use == for equality, while doing if (type == saving) { with a String is asking for trouble. That is
if (type == AccountType.CHECKING) {
} else if (type == AccountType.SAVINGS) {
will function as you would expect. Finally, it would be better to try and avoid the if chains and instead encapsulate whatever you plan to do with the account type into the enum itself when you can. For example,
Account acct = getAccount(accountNumber);
if (acct != null && acct.isValid()) {
acct.balance += acct.balance * type.getRate();
}
Related
If we have a Class Book and we want to calculate the score of a Book following some rules like "if the number of pages is lower than X then we need to substract Y from the score" and using an Hexagonal Architecture. Should we place this method calculateScore() in a separate Service in case this logic changes in the future using different fields or this reponsibility should be in the Domain itself?
1st approach
package com.xxx.domain;
[...]
public class Book {
[...]
public Double score() {
[...]
}
[...]
}
2nd approach
package com.xxx.application;
[...]
public interface ScoreService {
[...]
void calculateScore(Book book);
[...]
}
Should we place this method calculateScore() in a separate Service in case this logic changes in the future using different fields or this reponsibility should be in the Domain itself?
First the clean architecture is very clear when it comes to the question "Where should business logic be placed?".
Application agnostic business logic in the entities layer.
Application specific business logic in the use case layer.
But I think your question is about something a bit different, it's about anemic or rich domain models. I can't tell you every of my thoughts here, but I have written down most of them in the blog I linked in the sentence before.
The condensed statement of mine is
rich domain models combine data and logic while anemic models separate them.
Let's think about the anemic way...
If you place the logic in a separate service it usually means that you have to expose all properties of the book. You will make them public or at least package scope if the service is in the same package.
Your question also focuses on change. You make the statement that logic changes can be better handled if the logic is put in a separate service. That's true, but it comes at a cost.
It's true that an anemic model let you add logic easier, but it is also true that each logic (each service) must have the same interpretation of the anemic model. I mean each service must know how to modify the data structure properly to keep it consistent and that will be hard to maintain when the number of services grows.
But implementing the service can also be a good intermediate step, because it will give you a hint about cohesion. The cohesion usually shows you where to place a method. E.g.
public class ScoreService {
public BookScore calculateScore(Book book, BookRentals rentals){
int pageCount = book.getPageCount();
Author author = book.getAuthor();
// calculate a new value based on pageCount and the author
// ...
OtherValue ov = book.getSomeOtherValue();
// do something with ov
int rentalCount = rentals.getCountSince(someDate);
// ... and so on
}
}
When you look at the calculateScore above you will recognize that there are a lot of get invocations on Book and less on BookRentals. This is a hint that most of the data that calculateScore needs is placed in the Book. Thus the calculateScore's cohesion is higher to Book and the method might be placed in the Bookclass. E.g.
public class Book {
public BookScore getScore(BookRentals rentals){
int pageCount = this.getPageCount();
Author author = this.getAuthor();
// calculate a new value based on pageCount and the author
// ...
OtherValue ov = this.getSomeOtherValue();
// do something with ov
int rentalCount = rentals.getCountSince(someDate);
// ... and so on
}
}
The difference is obvious:
the number of method parameters decreases. Maybe you apply DDD and Book is an aggregation root and also has access to BookRentals. Then your parameters might decrease to zero.
Since most of the properties that getScore needs are located in the Book class, you might want to lower their visibilily to private. So that uncontrolled access is not allowed.
One question that often arises when developers put the logic in the entities is: "How can an entity access data from a data store?"
My solution is to just pass a repository to the methods that need it. E.g.
public class Book {
public BookScore getScore(BookRentalRepository repo){
// ...
int rentalCount = repo.getRentalCountSince(this, someDate);
}
}
Whatever way you want to go, anemic or rich, keep the logic in a POJO. Also keep in mind that a POJO can be more than a simple data structure.
I hope my answer helps you to make a decision for your specific application.
If the calc of the score depends only on the book state, i would create a method in the book entity to calc it.
Otherwise, if it depends on other domain objects also, i would create a domain service for calculating it.
Regarding to persist the score. I would persist it just if the calc process is very complicated and takes a lot of time. Otherwise, I wouldn't persist it and calc it when need it.
In case you persist jt, you have to consider that you have to recalculate it and persist the new value every time the other values it depends on change too.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I want to see an example of reaching directly into the code from a class that uses publicly declared data members to see an example of poor encapsulation so I can understand the good examples of encapsulation in OOP by contrasting with a bad example.(Being told to use encapsulation without a bad example is like being told not to steal without understanding what stealing is to me.) Thanks.
Suppose you have a Counter class that:
Starts with value = 0
Lets you increase the value by one (increment)
Lets you see the current value
A poorly-encapsulated version would directly expose the inner counter value:
class Counter {
public int value;
public Counter() {
this.value = 0;
}
public int increment() {
return ++this.value;
}
}
The problem, of course, is that users of the class can do this:
Counter c = new Counter();
System.out.println(c.value); // 0
c.increment();
System.out.println(c.value); // 1
c.value = 42;
System.out.println(c.value); // 42
Proper encapsulation corrects that:
class Counter {
private int value; // *** Private
public Counter() {
this.value = 0;
}
public int increment() {
return ++this.value;
}
public int getValue() { // *** Accessor
return this.value;
}
}
Now, there's no way¹ for the user of the class to directly set value.
Counter c = new Counter();
System.out.println(c.getValue()); // 0
c.increment();
System.out.println(c.getValue()); // 1
// No equivalent to `c.value = 42` is possible here¹
¹ (without using reflection)
Your question is a useful one, since understanding the reasons that encapsulation is important will help you avoid overgeneralizing the principle as well as help you understand when you've done it adequately.
You can find an example of poor encapsulation here: https://github.com/dotnet/training-tutorials/blob/master/content/csharp/getting-started/encapsulation-oop.md When the class in the example is used by other code to do something mundane, it create problems because the class hasn't been encapsulated. (Other examples might illustrate the problems that are created by poor encapsulation rather than a lack of encapsulation, but I understand you to want an example of the basic idea.)
Many times the problem that is created by not encapsulating your code is that properties and/or objects are updated or deleted when it is a copy of the object that you actually wish to update or delete.
Here are some relevant portions of the linked example. The first quote describes the problem that is created when the class lacks encapsulation:
Notice that in this example, the technique used to print the orders is a while loop that throws away each record as it prints it. This is an implementation detail, and if the collection this loop was working with were properly encapsulated, it wouldn't cause any issues. Unfortunately, even though a locally scoped orders variable is used to represent the collection, the calls to RemoveAt are actually removing records from the underlying Customer object. At the end of the program, both customers have 0 orders. This is not the intended behavior.
The second quote notes that the problem can be "solved" with a different implementation, but avoided altogether with encapsulation:
There are a variety of ways this can be addressed, the simplest of which is to change the while loop to a foreach, but the underlying problem is that Customer isn't encapsulating its Orders property in any way. Even if it didn't allow other classes to set the property, the List type it exposes is itself breaking encapsulation, and allowing collaborators to arbitrarily Remove or even Clear the contents of the collection.
What this example illustrates well is that the need for encapsulation isn't absolute, but it's most certainly a best practice.
In an e-commerce application, below are the high level API
interface Order{
public List<PaymentGroup> getPaymentGroups();
}
interface PaymentGroup{}
class PaymentGroupImpl implements PaymentGroup{}
class CreditCard extends PaymentGroupImpl{}
class GiftCard extends PaymentGroupImpl{}
class OrderManager{ //Manager component used to manipulate Order}
There is a need to add some utility methods like hasGiftCard(), hasCreditCard(), getGiftCards(), getCreditCards()
Two approaches -
1) Add these in Order. However, this would result in coupling between Order and PaymentGroup implementors (like CreditCard, GiftCard) Example -
interface Order {
public List<GiftCard> getGiftCards();
}
2) Move these to OrderManager.
class OrderManager{
public List<GiftCard> getGiftCards(Order order){}
}
I personally prefer 2), am just curious would there be any reason to choose 1) over 2)
I have two answers. One is what I'll call Old Skool OOP and the other I'll call New Skool OOP.
Let's tackle New Skool first. The GoF and Martin Fowler changed the way people look at OOP. Adding methods like hasGiftCard() leads to adding conditional logic/branching into the code. It might look something like this:
if (order.hasGiftCard()) {
//Do gift card stuff
} else {
//Do something else
}
Eventually this kind of code becomes brittle. On a big application, lots of developers will be writing predicate methods. Predicate methods assert something and return true or false. These methods usually start with the word "has", "is" or "contains". For example, isValid(), hasAddress(), or containsFood(). Still more developers write conditional logic that uses those predicate methods.
To avoid all of this conditional logic software engineers changed how they thought about object-orientation. Instead of predicate-methods-and-conditional-logic, they started using things like the strategy pattern, visitor pattern, and dependency injection. An example from your problem domain might look like this:
//Old Skool
if (this.hasCreditCard()) {
orderManager.processCreditCard(this.getCreditCards());
}
Here is another approach to solving the same problem:
//New Skool
for(PaymentItem each : getPaymentItems()){
each.process(this);
}
The New Skool approach turns the problem on its head. Instead of making the Order and OrderManager responsible for the heavy lifting the work is pushed out to the subordinate objects. These kind of patterns are slick because:
they eliminate a lot of "if" statements,
the code is more supple and it is easier to extend the application, and
instead of every developer making changes to Order and OrderManager, the work is spread out among more classes nd code merges are easier.
That's New Skool. Back in the day, I wrote a lot of Old Skool object-oriented code. If you want to go that route, here are my recommendations.
IMHO, you don't need both a PaymentGroup interface and a PaymentGroupImpl class. If all payment classes extend PaymentGroupImpl, then get rid of the interface and make PaymentGroup a class.
Add methods like isCreditCard(), isGiftCertificate() to the PaymentGroup class. Have them all return "false".
In the subclasses of PaymentGroup, override these methods to return true where appropriate. For example, in the CreditCard class, isCreditCard() should return "true".
In the Order class, create methods to filter the payments by type. Create methods like getCreditCards(), getGiftCertificates(), and so on. In traditional Java (no lambdas or helper libraries), these methods might look something like this
List getCreditCards() {
List list = new ArrayList();
for(PaymentGroup each : getPaymentGroups()){
if(each.isCreditCard()) {
list.add(each);
}
return list;
}
-In the Order class, create predicate methods like hasCreditCards(). If performance is not an issue, do this:
boolean hasCreditCards() {
return !getCreditCards().isEmpty();
}
If performance is an issue, do something more clever:
boolean hasCreditCards() {
for(PaymentGroup each : getPaymentGroups()){
if(each.isCreditCard()) {
return true;
}
return false;
}
}
Realize that if you add a new payment group, a code must be added in a lot of places in the Old Skool paradigm.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
Folks I'll start by apologising as I'm sure this has been answered elsewhere - I just can't find an answer that explains it in a way I understand! I'm doing an MSc conversion course and there are some elementary basics that I'm still struggling with this, including this one - why making a variable private is better.
Say I have a Java class called Person, with a print method. I could create it and define it as such:
public class Person
{
public String name;
public String telephoneNumber;
public void print()
{
System.out.println(name + " " + telephoneNumber);
}
}
Then, in a main class, I could write the following code:
class testPerson
{
public static void main(String[] args)
{
Person test;
test = new Person();
test.name = "Mary";
test.telephoneNumber = "01234 567890";
test.print();
}
}
If I did this, the test.print(); would produce the output:
mary 01234 567890
However, I know this is considered poor coding. Variables should be private inside a public class, as we don't want to allow people to see how this information is stored or to be able to edit information without authorisation.
So now, I'll edit the Person class to declare the two Strings private and add get and set methods, like so:
private String name;
private String telephoneNumber;
public void setName (String name)
{
this.name = name;
}
public void getName()
{
return name;
}
// same code for telephone methods.
Now, in the main class, I would change the methods of setting name and telephone to the following:
mary.setName("Mary");
mary.settelephoneNumber("01234 567890");
According to the lecture notes I'm following, this is more efficient (although could be made even more efficient by adding in a Person() method to allow for instantiation etc.)
However, I'm struggling to see why this is better.
In the former method of doing things, the user could directly access the variables. But even though by hiding the variables they can't directly access them, the user can indirectly access and modify them which produces the exact same outcome.
Why is it that this is preferred and what no doubt silly thing am I missing/overlooking?
Pizza Delivery Analogy
You order a Pizza for delivery.
Pizza boy knocks the door and expects you to pay for it.
You take out the money from your purse and hand it over to the delivery boy. (You are in control of hiding the internal details (drivers license etc.)) Alternatively,
You could hand over the purse to the delivery boy and ask him to take the money from it. By doing this you are no longer in control. You are exposing internal details.
Read about Information Hiding and Encapsulation is not information hiding.
It's not that it's more efficient, it's that it's more maintainable and a good practice.
For example, with setter methods, you could have your setTelephoneNumber actually check that the String is a valid telephone number before you actually do the setting. You couldn't possibly do that if you made the variable public. Using a setter from the very beginning means that you can go back and e.g. add validation later on, whereas if you had made the variable public, you would have to add a setter and modify all your users everywhere to use the setter instead of modifying the variable directly.
People will give you a million regurgitated reasons why it is better, but it is only better in some cases, not in all of them unequivocally. For example, take Java's own class GridBagConstraints—it has no methods at all (if you don't count clone, which it has anyway; all Java classes inherit it from Object). Why? Because there's a case where this is in fact more practical. And GridBagConstraints is a Java Bean in the purest sense: it's all about properties, no business logic there.
Let me report on another fact from practice: no setter ever validates its input; no getter ever calculates its result. In the world of JavaBeans, any such behavior will soon get in the way of the universal assumption that setters set, and getters get. Basically, if you diverge in any way from the exact equivalent of public fields, you lose.
The modern Java APIs, like Hibernate, acknowledge this fact by accepting naked public fields on an equal footing with JavaBean-style properties. Earlier versions didn't allow that, but as experience with Java accrues, the realization is finally dawning that public fields are OK.
You have to operate on the assumption that, at some point, someone else will use your code - and that someone else could be you, a year down the line. If you see a public property on a class, you should be able to assume that it's free for you to manipulate, if it's not to be directly modified you shouldn't be able to see it externally.
A good literal example would be the dimensions of a bitmap object. Most machines wouldn't like it if you tried to draw a bitmap of dimensions -10x-10, because such a thing would obviously be impossible to represent on a screen. If the width/height properties of this bitmap were simply public variables, it's possible they might be set to invalid values later on by a well-meaning coder (NEVER assume that it wouldn't happen), and when it came to render it - bang, you've got a frozen computer.
By hiding the variables and using a setter, you can prevent this ever happening:
private int _width = 10;
public void setWidth(int value)
{
//Prevent the value moving into invalid range:
if(value < 1)
value = 1;
if(value > 4096)
value = 4096;
//Now apply it
_width = value;
}
However, for speed and convenience you don't have to develop your code like this at first - just make sure you go through it afterward and hide what you need to!
there are also security issues to consider. a common example is a bank account. you have a balance, and you use deposit to put in money, and withdrawal to remove money. if balance was public, it could be modified without depositing or withdrawing money. that could be VERY bad.
within a method, you can put checks on things, such as making sure you don't take more money out of an account than actually exists. you can't really do that if you're accessing the values directly. it's about control.
I have a java class with a thousand line method of if/else logic like this:
if (userType == "admin") {
if (age > 12) {
if (location == "USA") {
// do stuff
} else if (location == "Mexico") {
// do something slightly different than the US case
}
} else if (age < 12 && age > 4) {
if (location == "USA") {
// do something slightly different than the age > 12 US case
} else if (location == "Mexico") {
// do something slightly different
}
}
} else if (userType == "student") {
if (age > 12) {
if (location == "USA") {
// do stuff
} else if (location == "Mexico") {
// do something slightly different than the US case
}
} else if (age < 12 && age > 4) {
if (location == "USA") {
// do something slightly different than the age > 12 US case
} else if (location == "Mexico") {
// do something slightly different
}
}
How should I refactor this into something more managable?
You should use Strategies, possibly implemented within an enum, e.g.:
enum UserType {
ADMIN() {
public void doStuff() {
// do stuff the Admin way
}
},
STUDENT {
public void doStuff() {
// do stuff the Student way
}
};
public abstract void doStuff();
}
As the code structure within each outermost if branch in your code looks pretty much the same, in the next step of refactoring you might want to factor out that duplication using template methods. Alternatively, you might turn Location (and possibly Age) into a strategy as well.
Update: in Java4, you can implement a typesafe enum by hand, and use plain old subclassing to implement the different strategies.
The first thing I would do with this code is create the types Admin and Student, both of which inherit from the base type User. These classes should have a doStuff() method where you hide the rest of this logic.
As a rule of thumb, any time you catch yourself switching on type, you can use polymorphism instead.
Thousands? Maybe a rules engine is what you need. Drools could be a viable alternative.
Or a Command pattern that encapsulates all the "do something slightly different" logic for each case. Store each Command in a Map with the concatentation of age, location, and other factors as the key. Lookup the Command, execute it, and you're done. Nice and clean.
The Map can be stored as configuration and read in on start up. You can add new logic by adding new classes and reconfiguring.
First - use enums for userType and location - then you can use switch statements (improves readability)
Second - use more methods.
Example:
switch (userType) {
case Admin: handleAdmin(); break;
case Student: handleStudent(); break;
}
and later
private void handleAdmin() {
switch (location) {
case USA: handleAdminInUSA(); break;
case Mexico: handleAdminInMexico(); break;
}
}
Further, identify duplicate code and put it in extra methods.
EDIT
If someone forces you to code Java without enums (like you're forced to use Java 1.4.2), use 'final static's instead of enums or do something like:
if (isAdmin(userType)) {
handleAdmin(location, age);
} else if (isStudent(userType)) {
handleStudent(location, age));
}
//...
private void handleAdmin(String location, int age) {
if (isUSA(location)) {
handleAdminInUSA(age);
} else if (isUSA(location)) {
handleAdminInMexico(age);
}
}
//...
private void handleAdminInUSA(int age) {
if (isOldEnough(age)) {
handleAdminInUSAOldEnough();
} else if (isChild(age)) {
handleChildishAdminInUSA(); // ;-)
} //...
}
The risk of this is not just that it is unsightly, but that it is very error prone. After a while, you could run into a risk of overlaps in your conditions.
If you can really distinguish the condition by user type, you can at the minimum break the body of each condition into a separate function. So that you check based on the type, and call an appropriate function specific to that type. A more OO solution is to represent each user as a class, and then override some calculation method to return a value based on the age. If you can't use classes but can at least use enums, then you will be able to do a nicer switch statement on the enums. Switches on Strings will only come in Java 7.
What worries me is situations of overlaps (e.g., two user types with some shared rules, etc.). If that ends up being the case, you might be better off representing the data as some external file (E.g., a table) which you would read and maintain, and your code will essentially operate as a driver that does the appropriate lookup in this data set. This is a common approach for complex business rules, since nobody wants to go and maintain tons of code.
I would probably first check whether you can parametrize the code doStuff and doSimilarStuff.
You may use Chain of Responsibility pattern.
Refactor if-else statements into classes with an interface IUserController for instance.
Initialize your chain within a list or a tree or any suitable data structure, and execute desired functionality in this chain. You may use Builder pattern to create mentioned data structure. It resembles to strategy pattern but in chain of responsibility pattern, an instance in the chain can call linked instance(s).
Moreover, you can model location specific functionality by using strategy pattern. Hope it helps.
If the code in the blocks fits within a few standard patterns, I would create a table with columns (type, location, minAge, maxAge, action), where 'action' is an enum indicating which of several types of processing to do. Ideally, this table would be read from a data file or kept in SQL.
Then, you can just do a table lookup in the Java code to determine the action to take for a user.
You could make userType an enum, and give it a method that performs all of your "do something slightly different" actions.
without more information there is no good answer
but fair guess would be this: use OO
first define a User, define Admin, Student and all other types of users and then let polymorphism take care of the rest
Based just on the variable names, I'm guessing that you should subclass User (or whatever it is that has a userType variable) into AdminUser and StudentUser (and possibly others) and use polymorphism.
Take a look at the Visitor pattern. It makes use of polymorphism but is a little more flexible in that it is easier to add new cases later.
The downside is you'd need some way to convert the state info into different instances. The benefit is a cleaner way to add behavior without having to modify your inheritance hierarchy.
You really need to break these cases into object methods. I'm assuming these strings and numbers are being pulled out of a database. Instead of using them in their raw form in giant nested conditional logic, you need to use these pieces of data to construct objects that model the desired interactions. Consider a UserRole class with a StudentRole and AdminRole subclasses, a Region class with USA and Mexico subclasses, and an AgeGroup class with appropriate partitioned subclasses.
Once you have this object oriented structure in place, you'll be able to make use of well understood object oriented design patterns to re-factor this logic.
Use OOP Concepts:
This is dependent of the rest of the design, but maybe you should have a user interface, Student,Admin interfaces the extends it and UsaStudent,MexicoStudent,UsaAdmin,MexicoAdmin implementation that do some stuff. Hold a User instance and just call its doStuff method.