I have some deep question about OOP architecture.
What is a proper way to communicate between object and its members?
Let me explain what I mean by some examples. (I use C++, but it's not related to the question at all.)
class Shield
{
int toughness;
//...
void broke();
};
class Human
{
String name;
int age;
//...
Shield my_shield;
void scream();
void equip_shield(Shield);
};
Human vadim;
Shield aegis;
vadim.equip_shield(aegis);
aegis.destroy();
So, now I want human to scream every time his or her shield is destroyed. But shield has no way to call its owner's method. He just doesn't know who is its owner.
One more example.
class Human
{
//...
void die();
};
class Crowd
{
vector<Humans> people;
//...
};
So, now I want crowd to tell all people to leave it if there are less than 10 people in the crowd. It's OK to crowd to tell such commands, but this check must be performed every time somebody dies in the crowd. So, again, human must somehow inform crowd that he or she is dead and ask crowd to recheck numbers of people in it.
The clear way to sort out this situation is to save the pointer to the crowd in every human. But it's dump way, because human can be in many crowds. Also there is synchronization problem here (same problem, actually, how can crowd know about the fact John left it?).
I believe that some trigger mechanism exists to solve such kinds of problems.
Thanks.
What you are looking for is the observer pattern.
With the observer pattern the crowd would subscribe to the humans in the crowd and when a human emits the "death" status it can recheck the count.
Likewise for the shield that could fire a "shield broke" event that the human could recognize and start yelling.
Related
We currently have the problem that our main class GameController is being pulled into every backend file in our game. We're wondering what are common solutions to this problem.
Here's a bit more about the game architecture. The game is a board game, so since ~90-95% of the time there isn't anything happening, the game is set up more like a rest API. It waits for a user prompt, when received, the msg is distributed to the respective components of the game and the proper logic is executed. No large update loops, just executes logic when prompted.
The problem is that as this msg cascades through the system, GameController acts more like a relay point between the systems. It's how the nodes communicate to each other so that all game components are updated properly. The problem is that it's created this system where all new/old classes contain a pointer to parentGame, so GameController is everywhere.
Are there any simple architectural solutions to avoid having every class contain a pointer to parentGame? Is this necessarily a bad thing?
Some example code:
class GameController {
bank: Bank
action: Action
...
}
class Bank {
parentGame: GameController
constructor(game: GameController) {
this.parentGame = game
}
}
class Action {
parentGame: GameController
constructor(game: GameController) {
this.parentGame = game
}
}
I don't believe it is necessarily a bad thing, but you might be able to clean it up a bit by wrapping it in some kind of eventing mechanism in the middle - in other words, pub/sub might give you some of the decoupling that you want.
It doesn't have to be anything that communicates via an external messaging service - that just introduces unnecessary overhead. The Observer Pattern comes to mind for me.
In this post I wanna to show you a little code example with several JS classes and ask you, whether this code is okay because of LSP or it violates encapsulation principles.
The _framesMonitor variable in this example is an instance of some 3-d party library vqt that we use inside Job class. _framesMonitor.stopListen() can throw exceptions, particularly vqt.Errors.ProcessExitError.
In this example below, is it okay to expose vqt.Errors.ProcessExitError type to the JobManager class (and it's okay because of LSP) or it violates
encapsulation revealing inner implementation details.
// Job.js
class Job {
constructor() {
this._framesMonitor = new FramesMonitor();
}
async stop() {
await this._framesMonitor.stopListen();
}
}
// JobsManager.js
class JobsManager {
async deleteJob() {
try {
await job.stop();
} catch(err) {
// vqt.Errors.ProcessExitError here
}
}
}
In this case Job is a concrete class and JobManager depends on it directly so it is allowed to know the specifics of Job as long as your intent is to have only one kind of Job.
However, if you conceptually plan to have many different Job implementations (whether the language supports explicit interfaces or not) then ideally JobManager should attempt to treat all Job generically and should do it's best not to depend on any Job details.
Therefore, JobManager may catch any error, but shouldn't ideally drive it's workflow based on arbitrary error details. If JobManager must know some level of details to issue the appropriate compensating actions then you should try to come up with a normalized JobFailureError (or even a return value) that provides the necessary information (it could as well carry the low-level error cause for logging purpose).
Finally, if somehow you need special case handling for every kind of job which cannot be normalized then it will be a question of trade-offs.
To keep error handling out of Job concerns you could allow the registration of special job handling strategies with the JobManager. Although this approach adheres to the Open-Closed Principle (OCP) it is also an implementation of the Service Locator which some sees as an anti-pattern. When adding new Job implementations you would also need to remember to add a corresponding handler.
E.g.
jobManager.registerHandler('some-job-type', function (job) {
//Special handling code job of some-job-type
});
If you do not mind some level of coupling between the concept of an error handler and a Job then you could do something like new SomeJob(errorHandler) or even having SomeJob couple to a specific handler.
I'd usually go for the Service Locator approach here, but I'm not sure if we can say it's an absolute best in every similar scenarios.
For instance, if you were using a static typed language perhaps using double-dispatch techniques or even pattern matching if available would be better because you could get compile-time feedback.
I don't really understand why it's generally good practice to make member variables and member functions private.
Is it for the sake of preventing people from screwing with things/more of an organizational tool?
Basically, yes, it's to prevent people from screwing with things.
Encapsulation (information hiding) is the term you're looking for.
By only publishing the bare minimum of information to the outside world, you're free to change the internals as much as you want.
For example, let's say you implement your phone book as an array of entries and don't hide that fact.
Someone then comes along and writes code which searches or manipulates your array without going through your "normal" interface. That means that, when you want to start using a linked list or some other more efficient data structure, their code will break, because it's used that information.
And that's your fault for publishing that information, not theirs for using it :-)
Classic examples are the setters and getters. You might think that you could just expose the temperature variable itself in a class so that a user could just do:
Location here = new Location();
int currTemp = here.temp;
But, what if you wanted to later have it actually web-scrape information from the Bureau of Meteorology whenever you asked for the temperature. If you'd encapsulated the information in the first place, the caller would just be doing:
int currTemp = here.getTemp();
and you could change the implementation of that method as much as you want. The only thing you have to preserve is the API (function name, arguments, return type and so on).
Interestingly, it's not just in code. Certain large companies will pepper their documentation with phrases like:
This technical information is for instructional purposes only and may change in future releases.
That allows them to deliver what the customer wants (the extra information) but doesn't lock them in to supporting it for all eternity.
The main reason is that you, the library developer, have insurance that nobody will be using parts of your code that you don't want to have to maintain.
Every public piece of your code can, and inevitably will get used by your customers. If you later discover that your design was actually terrible, and that version 2.0 should be written much better, then you realise that your paying customers actually want you to preserve all existing functionality, and you're locked in to maintaining backwards compatibility at the price of making better software.
By making as much of your code as possible private, you are unreservedly declaring that this code is nobody's business and that you can and will be able to rewrite it at any time.
It's to prevent people from screwing with things - but not from a security perspective.
Instead, it's intended to allow users of your class to only care about the public sections, leaving you (the author) free to modify the implementation (private) without worrying about breaking someone else's code.
For instance, most programming languages seem to store Strings as a char[] (an array of characters). If for some reason it was discovered that a linked list of nodes (each containing a single character) performed better, the internal implementation using the array could be switched, without (theoretically) breaking any code using the String class.
It's to present a clear code contract to anyone (you, someone else) who is using your object... separate "how to use it" from "how it works". This is known as Encapsulation.
On a side note, at least on .NET (probably on other platforms as well), it's not very hard for someone who really wants access to get to private portions of an object (in .NET, using reflection).
take the typical example of a counter. the thing the bodyguard at your night club is holding in his hands to make his punch harder and to count the people entering and leaving the club.
now the thing is defined like this:
public class Counter{
private int count = 0;
public void increment()
{
count++;
}
public void decrement()
{
count--;
}
}
As you can see, there are no setters/getters for count, because we don't want users (programmers) of this class, to be able to call myCounter.setCount(100), or even worse myCounter.Count -= 10; because that's not what this thing does, it goes up one for everyone entering and down for everyone leaving.
There is a scope for a lot of debate on this.
For example ... If a lot of .Net Framework was private, then this would prevent developers from screwing things up but at the same time it prevents devs from using the funcionality.
In my personal opinion, I would give preference to making methods public. But I would suggest to make use of the Facade pattern. In simple terms, you have a class that encapsulates complex functionality. For example, in the .net framework, the WebClient is a Facade that hides the complex http request/response logic.
Also ... Keep classes simple ... and you should have few public methods. That is a better abstraction than having large classes with lots of private methods
It is useful to know how an object s 'put together' have a look at this video on YouTube
http://www.youtube.com/watch?v=RcZAkBVNYTA&list=PL3FEE93A664B3B2E7&index=11&feature=plpp_video
I just started learning OOP and I'm finding it really hard to decide where functionality belongs. Let's use a down vote in SO for our example:
When we cast one, the following must happen in a transaction:
Decrement the voter's rep and downVotes count.
Decrement the recipient's rep.
Decrement the post score.
So...
How do we determine which action belongs to which object?
Where would such functionality live? In the DAO layer, services layer, or the actual objects themselves?
It becomes increasingly tricky when objects interact with each other, such as in my example. It's often hard to decide what function belongs to what object and so on...
Take a look at SOLID principles of OO design, Coupling & Cohesion.
OO can be used in many places, it is not limited to e.g. your Business Layer. You can write your Javascript object-oriented.
I'd model your example SO domain similar to this (in C#). This is idealistic OO code, and in real world some compromises would be made, such as making fields public for my ORM. What I am trying to show - each object is responsible for its data, noone else can change it directly; they must ask that object to do something, by calling one of the public methods.
public class User
{
private int _reputation;
private int _downvotes;
public void Downvote(Post post)
{
DecreaseReputation();
IncrementDownvotes();
post.Downvote();
}
public void RegisterDownvote()
{
DecreaseReputation();
}
private void DecreaseReputation()
{
_reputation--;
}
private void IncrementDownvotes()
{
_downvotes++;
}
}
public class Post
{
private int _score;
private User _poster;
public void Downvote()
{
DecreaseScore();
_poster.RegisterDownvote();
}
private void DecreaseScore()
{
_score--;
}
}
This is not an easy question to answer and sounds more like a design-pattern question than an OOP question per se. In the case of SO (I am making an assumption based on assumed design patterns for their site), all the "layers" of the design-pattern are involved in what you are calling a "transaction" (not a DB term I assume the way you are using it). The UI layer or View accepts the "down vote" and makes a what appears to be an ajax request most likely to a layer that handles business rules, which determines what actually happens when a "down vote" is cast against a user. At that point, the business layer makes requests of the data layer to update a database somewhere to update the user's score, reputation, etc. This also may be performed a little bit differently using web services, who knows what's under the hood here at SO. As far as OOP; I am sure there is a lot of OOP under the hood, everywhere, in all the layers, scripting and other languages perhaps, but I would imagine that in the case of your example, SO is not passing around a "User" class object when a vote is cast; there is no need to.
Here is the very popular MVC design pattern for example: http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
Q1.
In my university studies of object-oriented modelling and design they recommend thinking about what an object can do for its method, and what its responsibilities are for its attributes. All attempts at clarification have resulted in further confusion.
This tends to generate a class diagram with actors who have all the actions, and inner classes which only hold data.
This doesn't seem correct. Is there another way of thinking about how to model the objects?
Q2. Also, the course seems to emphasize modelling the objects after their real-world counterparts but it doesn't necessarily make sense in the domain model. IE. In a medical practice, they have Patient: CreateAppointment(), CancelAppointment() but that is not how it would be implemented (you would modify a the appointment collection instead). Is there another way of thinking about this?
Example Q1
Secretary: RecordAppointment(), RecordAppointmentCancellation()
Appointment: time, date,... (no methods)
Example Q2
Doctor: SeePatient()
While SeePatient is a use-case, it does not make sense for a method on the actual class. How do you think about this?
Unfortunately, the roadblock you've hit is all too typical in academia. Academic projects tend to start with video rental stores, libraries or student registration systems (yours is a variance of this with a doctor's office) and then inheritance is taught with animals. The guideline you've provided is also very typical
they recommend thinking about what an object can do for its method, and what its responsibilities are for its attributes
In fact when beginners ask I usually explain an object's property's are the things it knows about itself and its methods are the things it knows how to do. Which is really just another way of saying exactly what you have there. As you've discovered this way of thinking quickly breaks down when you start discussing more tangible systems and not just examples.
For instance the guideline works pretty well with this object:
public class Tree
{
public int Height { get; set; }
public void Grow(int byHowMuch)
{
Height += byHowMuch;
}
}
While this certainly fits the bill your right to think that it doesn't "feel" right:
public class Secretary
{
public void MakeAppoinment(Patient patient)
{
//make the appointment
}
}
So what's the solution? It's a matter of taking what you are being taught and applying it. Learning and understanding design patterns will help a lot with developing systems which are more functional than a tree that knows how to grow.
Recommended reading:
Design Patterns: Elements of Reusable Object-Oriented Software (also known as the Gang of Four or GoF)
Head First Design Patterns
Head First Object-Oriented Analysis and Design
To solve the issue you're been presented I would probably use a combination of inherited person classes and interfaces, which would perform their actions through a series of service classes. Essentially a secretary, doctor, and patient would all inherit from person and each of these classes could be passed to accompanying service classes. The service classes may or may not do things like SeePatient(). Please don't take this example to mean that person classes wouldn't have methods.
Stack Overflow has more than a few related questions which may be of use:
Is Single Responsibility Principle a rule of OOP?
Are there any rules for OOP?
why is OOP hard for me?
Additionally, it would be good to check out:
Single responsibility principle
Don't repeat yourself
PrinciplesOfOod
Finally, there isn't a single definition of what makes an application object oriented. How you apply patterns, principles etc. will define your program. The fact that you are asking yourself these questions shows that you are on the right track.
Q1
Is it possible responsibilities of your objects should be interpreted as authorization or contract requirements, as in what actions they should take? So, to take a medical example from your Q2, an object with a Scheduler role (think C#/Java interface, or Obj-C protocol) has attributes around CanEditAppointments or EditsAppointments.
Q2
From a use case perspective, a patient may be able to create an appointment, and so you might implement a Patient in your object model with a method to CreateAppointment(). But, in terms of encapsulation, you would likely instantiate an Appointment object in CreateAppointment(), and then call methods or set properties on the Appointment object to set its time, date, patient, physician, etc.
And because the Appointment collection is likely to be permanent storage like a database, it would likely be the Appointment object's responsibility to add itself to the collection (Appointment.Schedule() goes through your data access layer to save itself to the database).
That also ties back to your Q1, in that the Appointment object's responsibility is to save itself, so it might implement an ISaveAppointment interface that requires fields and methods to carry it out. It also is the Appointment's responsibility to have a date, and time, and patient, etc., before being saved, and so the ISaveAppointment interface should require they exist, and Appointment.Schedule() should validate the values are correct or have been previously validated.
You are right that in many cases there are higher order things which more naturally contain behaviour, like the system, or the user.
You can model this behaviour in classes as static methods which operate on the data model. It isn't OO, but it's fine. You can group related methods together into such classes, and soon you have the notion of "services", as in service oriented programming.
In Java there are specifications and standards for creating such classes, namely the stateless session bean in EJB. The Spring Framework has similar notions with the stereotype "Service" which can be applied to classes to tag them as being facades for business logic.
A service is then a component which encapsulates a certain functionality or behaviour in the system. It operates on a given object model (either its own internal one, or the more general business object model from the system). If you take your use cases and create services which relate directly to them, you can write very maintainable software.
The DCI Architecture is a formalisation of this and an attempt to do the same, but at the same time trying to stay true to object orientation, by adding behaviour to objects as they need it.
I still experience the confusion: "am I telling you to do something else" or "am I doing something someone else asked of me"?
Perhaps all you have to do is play Barbie's, or G.I. Joe's to understand object interaction and where responsibilities go. G.I. Joe got wounded (or Barbie broke a nail) so he calls the Dr's office. "Hey doc, this is Joe, I need an appointment." So you, the kid, tell Barbie to go to the doctor, who needs to know the doc to call and how to call - a reference and public MakeAppointment() method. The Dr. office needs to put the appointment on the books - it's own BookAppointment() method that is the office's procedure for handling appointment requests.
public abstract GenderAppropriateDolly {
protected DrOffice Drkilldare;
public override MakeAppointment() {throw new NotImplementedException();}
}
public class GIJoe : GenderAppropriateDolly {
DrKilldare = new DrOffice();
List<Appointment> myAppointments = new List<Appointment>;
public void MakeAppointment () {
myAppointments.Add(DrKilldare.BookAppointment(this));
}
}
public class DrOffice {
List<Appointment> officeAppointments = new List<Appointments>;
public Appointment BookAppointment(GenderAppropriateDolly forWhom) {
Appointment newappt = new Appointment(formWhom);
this.Appointments.Add(newappt);
return newappt;
}
}
public class Kid {
GenderAppropriateDolly myRoleModel = new GIJoe();
// Joe got wounded so ...
myRoleModel.MakeAppointment();
}