These days, I hear almost everywhere about 'event driven' programming.
Wikipedia says:
In computer programming, event-driven programming is a programming paradigm in which the flow of the program is determined by events such as user actions (mouse clicks, key presses), sensor outputs, or messages from other programs/threads. Event-driven programming is the dominant paradigm used in graphical user interfaces and other applications (e.g. Javascript web applications) that are centered around performing certain actions in response to user input.
Isn't this exactly our old friend OOP? And if this is not OOP what is the difference?
Object Oriented Programming (OOP) and Event-Driven Programming (EDP) are orthogonal, which means that they can be used together.
In OOP with EDP all OOP principles (encapsulation, inheritance and polymorphism) stay intact.
In OOP with EDP objects acquire some mechanism of publishing event notifications and subscribing to event notifications from other objects.
The difference between OOP with / without EDP is control flow between objects.
In OOP without EDP control moves from one object to another object on a method call. Object mainly invokes methods of other objects.
In OOP with EDP control moves from one object to another object on event notification. Object subscribes on notifications from other objects, then waits for notifications from the objects it is subscribed on, does some work based on notification and publishes it's own notifications.
Conclusion: OOP+EDP is "exactly our old friend OOP" with control flow inverted thanks to Event-Driven Design.
Object Oriented Programming is defined by the pairing together of data and actions into a model of a real world object. Event driven programming is a style of programming in which we have a server, whether it be on a communications port or a user interface, waiting for an input command. It will then process that command and display/produce desired results.
Most event driven languages are object oriented. The objects await the events. A program in an object oriented language is not necessarily event driven, and event driven programming does not necessarily require an object oriented language. They are unrelated.
The algorithm of a sequential (non-event-driven) program is like a recipe: begin at the beginning, work through until you get to the end, then stop.
An event-driven program is more like the controls of a car: anything can happen any time in any order.
The Object-Oriented principle seems more applicable to an event-driven model because each of the "controls" is basically unrelated to the others (separation of concerns), and order of events is mostly not important, as is coincidence in time: you can turn on the wipers, turn off the defroster, steer and accelerate all at the same time, and the actions do not affect each other. That is also possible in some cases with a recipe, but it is up to the chef (compiler / optimizer / cpu) to deduce it.
A sequential program can be OO: nobody minds if the blender and the oven are disconnected and do their own thing. I hope this was a useful analogy.
My stab at it. Here are three metaphors:
Event programming seems to be similar to how hardware buses work: a bus is used for peripherals to talk to one another. Similarly, a cell tower is the message bus by which cellphones talk to one another. Also consider the good old Star Network topology model (https://en.wikipedia.org/wiki/Star_network). Heck, look at how a home router connects computers and IoT devices to a home network.
Instead of peripherals or cellphones or devices, we code objects. Instead of sending packets along a transmission protocol, we send events or messages to a message broker (a message queue, for instance, or Kafka). The event is available to be acted upon by whomever is interested in it, or in the case of a workflow, the event is expected to be worked by someone in particular and the sender will expect to find a resulting event with a response appropriate to the outcome.
ASIDE: Lessons Learned
Potentially, we therefore also have solutions about problems that hardware manufacturers and telecom engineers have already encountered and solved regarding event-driven messaging.
Related
Encapsulation lends itself to hierarchical "silos" or "trees" of objects, with a given application's major functionalities decomposed into core trunks, each further decomposed into sub-functionalities instantiated as sub-branch member objects of their respective branches.
As an example, suppose I'm programming a GUI in QT. To separate GUI elements from business logic, for every widget I have a class for the GUI elements, a class for the business logic associated with the GUI elements, and what I'll call a controller which serves as a container for both and exists primarily to pass signals/slots in between. I understand this pattern to be called dependency injection.
Let's suppose our application has 2 windows A and B.
Window A contains 2 independent widgets that have separate business functions i and ii, so we might have the structure A::i and A::ii, where :: is "contains an instance of" and not "extends".
Then i and ii both contain gui and business logic units, so we have A::i::business and A::i::gui.
Now, suppose A::i::business and A::ii::business want to pass information between each other, or engage in bidirectional communication with the model-view for my database, identified as MV. Generally speaking, what are my options for doing this?
What I've thought of so far:
1) Pass signals up and down the tree, i.e., the Verilog solution. This seems the most strictly object oriented, but most tedious.
2) Have a flatter architecture to ease the implementation of solution 1). This hurts encapsulation.
3) Make A::i::business and A::ii::business public all the way down, and have either the other object or a third-party shared class access A::i::business or A::ii:business directly. This hurts encapsulation.
4) Have a relatively unencapsulated object, like the database MV or some other form of "shared storage", exist in a public form near the top level of the program with few/ no super-containers. This seems most appealing, as the relatively encapsulated objects can stay encapsulated and communicate through unidirectional reading/ writing to something that's unencapsulated. However, if I want other objects to perform actions based on changes shared storage, some way of notifying the dependent objects while keeping them private is necessary. This might be called the "multi-threading inspired" or "multi-processing inspired" model of communication.
And any other suggestions you all may have.
I've read this post here, but at my level of understanding, the solutions in the accepted answer such as controller, listener and pub-sub, refer to general design patterns that don't seem to commit to a solution for the concrete problem of how to route signals and make decisions about public/ private accessibility of member classes. It may be the case that these solutions have associated conventions for where the communication objects go and how they access the different variables in either silo that I'm not familiar with.
Most generally speaking, I seem to be running into a general problem of communication across container-trees in well-encapsulated programming.
For future reference, is there a general term for this problem to aide future searching? Is my architectural approach of having the object-container structure directly reflecting the tree-decomposition of application functionality lending itself to too hierarchical a design, and would a different pattern of object containment and cross-branch communication be more optimal?
I've noticed that my dependency injected, observer-pattern-heavy code (using Guava's EventBus) is often significantly more difficult to debug than code I've written in the past without these features. Particularly when trying to determine when and why observer code is being called.
Martin Oderski and friends wrote a lengthy paper with an especially alluring title, "Deprecating the Observer Pattern" and I have not yet made the time to read it.
I'd like to know what is so wrong with the observer pattern and so much better about the (proposed or other) alternatives to lead such bright people to write this paper.
As a start, I did find one (entertaining) critique of the paper here.
Quoting directly from the paper:
To illustrate the precise problems of the observer pattern,
we start with a simple and ubiquitous example: mouse dragging.
The following example traces the movements of the
mouse during a drag operation in a Path object and displays
it on the screen. To keep things simple, we use Scala closures
as observers.
var path: Path = null
val moveObserver = { (event: MouseEvent) =>
path.lineTo(event.position)
draw(path)
}
control.addMouseDownObserver { event =>
path = new Path(event.position)
control.addMouseMoveObserver(moveObserver)
}
control.addMouseUpObserver { event =>
control.removeMouseMoveObserver(moveObserver)
path.close()
draw(path)
}
The above example, and as we will argue the observer
pattern as defined in [25] in general, violates an impressive
line-up of important software engineering principles:
Side-effects Observers promote side-effects. Since observers
are stateless, we often need several of them to simulate
a state machine as in the drag example. We have to save
the state where it is accessible to all involved observers
such as in the variable path above.
Encapsulation As the state variable path escapes the scope
of the observers, the observer pattern breaks encapsulation.
Composability Multiple observers form a loose collection
of objects that deal with a single concern (or multiple,
see next point). Since multiple observers are installed at
different points at different times, we can’t, for instance,
easily dispose them altogether.
Separation of concerns The above observers not only trace
the mouse path but also call a drawing command, or
more generally, include two different concerns in the
same code location. It is often preferable to separate the
concerns of constructing the path and displaying it, e.g.,
as in the model-view-controller (MVC) [30] pattern.
Scalablity We could achieve a separation of concerns in our
example by creating a class for paths that itself publishes
events when the path changes. Unfortunately, there is no
guarantee for data consistency in the observer pattern.
Let us suppose we would create another event publishing
object that depends on changes in our original path, e.g.,
a rectangle that represents the bounds of our path. Also
consider an observer listening to changes in both the
path and its bounds in order to draw a framed path. This
observer would manually need to determine whether the
bounds are already updated and, if not, defer the drawing
operation. Otherwise the user could observe a frame on
the screen that has the wrong size (a glitch).
Uniformity Different methods to install different observers
decrease code uniformity.
Abstraction There is a low level of abstraction in the example.
It relies on a heavyweight interface of a control
class that provides more than just specific methods to install
mouse event observers. Therefore, we cannot abstract
over the precise event sources. For instance, we
could let the user abort a drag operation by hitting the escape
key or use a different pointer device such as a touch
screen or graphics tablet.
Resource management An observer’s life-time needs to be
managed by clients. Because of performance reasons,
we want to observe mouse move events only during a
drag operation. Therefore, we need to explicitly install
and uninstall the mouse move observer and we need to
remember the point of installation (control above).
Semantic distance Ultimately, the example is hard to understand
because the control flow is inverted which results
in too much boilerplate code that increases the semantic
distance between the programmers intention and
the actual code.
[25] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design
patterns: elements of reusable object-oriented software.
Addison-Wesley Longman Publishing Co., Inc., Boston, MA,
USA, 1995. ISBN 0-201-63361-2.
I believe the Observer pattern has the standard drawbacks that come with decoupling things. The Subject gets decoupled from Observer but you cannot just look at its source code and find out who observes it. Hardcoded dependencies are usually easier to read and think about but they are harder to modify and reuse. It's a tradeoff.
As to the paper, it does not address the Observer pattern itself but a particular usage of it. In particular: multiple stateless Observer objects per single object being observed. This has the obvious drawback of the separate observers needing to synchronize with each other ("Since observers are stateless, we often need several of them to simulate
a state machine as in the drag example. We have to save
the state where it is accessible to all involved observers
such as in the variable path above.")
The above drawback is specific to this kind of usage, not to the Observer pattern itself. You could as well create a single (stateful!) observer object that implements all the OnThis, OnThat,OnWhatever methods and get rid of the problem of simulating a state machine across many stateless objects.
I will be brief because I'm new to the topic (and didn't read that specific article yet).
Observer Pattern is intuitively wrong: The Object to be observed knows who is observing (Subject<>--Observer).
That is against real-life (in event-based scenarios). If I scream, I have no idea who is listening; if a lightening, hits the floor... lightning doesn't know that there is a floor till it hits!. Only Observers know what they can observe.
When this kind of of things happen then software use to be a mess -because constructed against our way of thinking-.
It is as if and object knew what other objects can call his methods.
IMO a layer such as "Environment" is the one in charge of taking the events and notifying the affected. (OR mixes the event and the generator of that event)
Event-Source (Subject) generates events to the Environment. Environment delivers the event to the Observer. Observer could register to the kind of events that affects him or it is actually defined in the Environment. Both possibilities make sense (but I wanted to be brief).
In my understanding the Observer Pattern puts together environment & subject.
PS. hate to put in paragraphs abstract ideas! :P
For an example of encapsulation i can think of the interaction between a user and a mobile phone. The user does not need to know the internal working of the mobile phone to operate, so this is called abstraction. But where does encapsulation fit in to this example? Could someone please shed some light on this?
Encapsulation is a way to achieve "information hiding" so, following your example, you don't "need to know the internal working of the mobile phone to operate" with it. You have an interface to use the device behaviour without knowing implementation details.
Abstraction on the other side, can be explained as the capability to use the same interface for different objects. Different implementations of the same interface can exist. Details are hidden by encapsulation.
Abstraction : you'll never buy a "device", but always buy something more specific : iPhone, GSII, Nokia 3310... Here, iPhone, GSII and N3310 are concrete things, device is abstract.
Encapsulation : you've got several devices, all of them have got a USB port. You don't know what kind of printed circuit there's back, you just have to know you'll be able to plug a USB cable into it.
Abstraction is a concept, which is allowed by encapsulation. My example wasn't the best one (there's no real link between the two blocks).
You can do encapsulation without using abstraction, but if you wanna use some abstraction in your projects, you'll need encapsulation.
Encapsulation is to hide the variables or something inside a class, preventing unauthorized parties to use. So the public methods like getter and setter access it and the other classes call these methods for accessing
Abstraction involves the facility to define objects that represent abstract "actors" that can perform work, report on and change their state, and "communicate" with other objects in the system.
Consider the below real time example:
Encapsulation:
As a driver you know how to start the car by pressing the start button and internal details of the starting operations are hidden from you. So the entire starting process is hidden from you otherwise we can tell starting operation is encapsulated from you.
OR
The driving wheel is encapsulated the process of rotating the wheel from you.
Abstraction:
Before mentioning anything about abstraction, we can take three different users here (I am calling them as entity)
1) You 2) Local Mechanic 3) Expert
You Entity: Since you know only to start the car by pressing a button and all other operations behind the scene are abstracted from you.
Local Mechanic Entity: Our local mechanic knows some of the implementation of starting the car, i.e. he can open car's bonnet and check the battery cable or chock etc. So in short Local Mechanic Entity knows some of the implementations of the car.
Expert Entity: Since our expert (Designer of the car) mechanic knows all the operations of our car, he can repair it very quickly. So in short Expert Entity knows all the implementations of the car.
The car's operation is completely abstracted from you and it is partially implemented to Local Mechanic Entity and fully implemented to Expert Entity. So you are an abstract class having only abstract methods, Local Mechanic Entity has extended You(Since he is also an ordinary user) and he implemented some of the methods and last our expert Entity extending Local Mechanic and implementing all the methods.
I think this is a good example.
In General words,Abstraction is Just Hiding the complex things behind a particular Procedure to make the procedure look simple.
Example:Monitor ON/OFF::--The user doesn't need to know much about all the chips functioning that happens when Monitor is switched ON or OFF..All he needs to know is On Function ON-Monitor is On and on function OFF-Monitor is off...
Or Better Look for a car--Everyone Knows that There's a special Gear machine Which changes the gear,nobody bother to know what all functionality undergoes for a gear to change..So,That's abstraction(avoiding unwanted implementations to prevent Complexity).
So,If a developer provides a good abstraction, users won't be tempted to peek at the object's internal mechanisms.
Abstraction is achieved by making class abstract having one or more methods abstract. Which is nothing but essential characteristic which should be implemented by the class extending it.
e.g. when you inventing/designing a car you define a characteristics like car should have 4 doors, break, steering wheel etc… so anyone uses this design should include this characteristics. Implementation is not the head each of abstraction. It will just define characteristics which should be included.
Encapsulation is restricting a user to follow a particular procedure to access control of a particular process.It Just provides safety and ensures system robustness.
Example:We can consider The HR in a company as a person that works on the principle of Encapsulation.i.e. we cannot talk to other departments directly we need to communicate through them through HR.This ensures security and better maintenance of company's records.
Together we can take example of a UNDER CONSTRUCTION BUILDING..where we can say that things like 'no. of managers' required,Types of Materials,No of workers etc as abstraction as they need to there in every Building Construction.
But,at the same time,Inclusion of every such field into a CONTRACTOR which acts as a mediator between the workers and the Building-Investor can be looked upon as Encapsulation.
As,It hides all the above properties into one Entity.
Hence If you would have understood till now you can say that
abstraction is just a subset of ENCAPSULATION.i.e.Every entity that
performs abstraction is encapsulated internally but every thing that
shows encapsulation need not be abstraction always.
e.g. .ToString() Method defined in almost every class is implementation of Abstraction because We don't the functionaltiy Within,all we care is that it changes almost everything to string.And as it assembles a s a unit,it is encapsulated too..But,The private members that we hide and access through Properties is an example of encapsulation only as it is done basically keeping data security in mindd..!!
Hope This answers your Question..!!
Everything has many properties and behaviours so take whatever object you want TV, Mobile, Car, Human or anything.
Abstraction:
Process of picking the essence of an object you really need
In other words, pick the properties you need from the object
Example:
a. TV - Sound, Visuals, Power Input, Channels Input.
b. Mobile - Button/Touch screen, power button, volume button, sim port.
c. Car - Steering, Break, Clutch, Accelerator, Key Hole.
d. Human - Voice, Body, Eye Sight, Hearing, Emotions.
Encapsulation:
Process of hiding the details of an object you don't need
In other words, hide the properties and operations you don't need from the object but are required for the object to work properly
Example:
a. TV - Internal and connections of Speaker, Display, Power distribution b/w components, Channel mechanism.
b. Mobile - How the input is parsed and processed, How pressing a button on/off or changes volumes, how sim will connect to service providers.
c. Car - How turning steering turns the car, How break slow or stops the car, How clutch works, How accelerator increases speed, How key hole switch on/of the car.
d. Human - How voice is produced, What's inside the body, How eye sight works, How hearing works, How emotions generate and effect us.
ABSTRACT everything you need and ENCAPSULATE everything you don't need ;)
The wording of your question is odd - Abstraction vs Encapsulation?
It should be - someone explain abstraction and encapsulation...
Abstraction is understanding the essence of the thing.
A real world example is abstract art. The artists of this style try to capture/paint the essence of the thing that still allows it to be the thing. This brown smear of 4 lines captures the essence of what a bull is.
Encapsulation is black boxing.
A cell phone is a great example. I have no idea how the cell phone connects to a satellite, tower, or another phone. I have no idea how the damn thing understands my key presses or how it takes and sends pictures to an email address or another phone number. I have no idea about the intricate details of most of how a modern smart phone works. But, I can use it! The phones have standard interfaces (yes - both literal and software design) that allows someone who understand the basics of one to use almost all of them.
How are the two related?
Both abstraction and encapsulation are underlying foundations of object oriented thought and design. So, in our cell phone example. The notion of a smart phone is an abstraction, within which certain features and services are encapsulated. The iPhone and Galaxy are further abstractions of the higher level abstraction. Your physical iPhone or Galaxy are concrete examples of multiple layers of abstractions which contain encapsulated features and services.
Abstraction
Means We focus on the essential qualities of some thing rather than one specific example and we automatically discard what is unimportant or irrelevant.
Example
We are writing a bank account class,essential qualities of bank account are Opening date, Account title,Account number,Balance etc...
Encapsulation
Means the idea of capsulation or surrounding some thing not just to keep the content together but also to protect and restrict form accessing out side.Along with secrecy It's about reducing dependencies between different parts of the application.
Example
In our Bank account class Someone accessing the attribute of Balance and trying to change it ,Attempt can be successful if there is no encapsulation.
Encapsulation is hiding information.
Abstraction is hiding the functionality details.
Encapsulation is performed by constructing the class. Abstraction is achieved by creating either Abstract Classes or Interfaces on top of your class.
In the example given in the question, we are using the class for its functionality and we don't care about how the device achieves that. So we can say the details of the phone are "abstracted" from us.
Encapsulation is hiding WHAT THE PHONE USES to achieve whatever it does; Abstraction is hiding HOW IT DOES it.-
Encapsulation helps in adhering to Single Responsibility principle and Abstraction helps in adhering to Code to Interface and not to implement.
Say I have a class for Car : Service Provider Class and Driver Class : Service Consumer Class.
For Abstraction : we define abstract Class for CAR and define all the abstract methods in it , which are function available in the car like : changeGear(), applyBrake().
Now the actual Car (Concrete Class i.e. like Mercedes , BMW will implement these methods in their own way and abstract the execution and end user will still apply break and change gear for particular concrete car instance and polymorphically the execution will happen as defined in concrete class.
For Encapsulation : Now say Mercedes come up with new feature/technology: Anti Skid Braking, while implementing the applyBrake(), it will encapsulate this feature in applyBrake() method and thus providing cohesion, and service consumer will still access by same method applyBrake() of the car object.
Thus Encapsulation lets further in same concrete class implementation.
I feel like encapsulation may make more sense to discuss when you see HOW NOT TO DO in programming. For example, consider a Car class as below.
class Car{
public float speed =0;
public boolean isReverse = false;
public boolean isStarted = false;
}
The client code may use above car class as below.
class Main{
public static void main(args String[]){
Car car = new Car();
// No need to start??
car.speed = 100; // Turbo mode directly to 100
car.speed = 0; // Turbo break
}
}
See more at: http://brevitaz.com/encapsulation-example-benefits-java/
This is uncontrolled access to car speed and other variables. By encapsulation, Car class can have complete control over how the data variables within car class can be modified.
Any concrete entity that has some behavior is example of Encapsulation. The behavior is provided by wrapping up something and hiding something from client.In case of mobile, it is signals, chips, circuits, battery and so on.
For abstraction of the same example - normal user may say I am ok with anything using which I can make calls and receive calls. This abstraction can be substituted by any concrete mobile. Check out Abstraction examples.
Let me give my 2 cents of a real-world example-analogy close to IT.
Lets say you have a subscription site, e.g a wordpress site
Each user has a role, eg admin, subscriber and so on. Many users can be admins, subscribers etc..
So abstraction here is reflected in the fact that any user with admin role can do a set of things, it does not matter which specific user this is (this is an example of abstraction).
On the other hand, subscriber users do not have access to certain settings of the site, thus some internals of the application are encapsulated for plain subscribers (this is an example of encapsulation)
As one can see abstraction and encapsulation are relative concepts, they apply with respect to something specific.
One can follow this line of reasoning and explain polymoprhism and inheritance.
For example super-admin users could do all the things admin users could do, plus some more. Moreover, if admin roles get an update in functionality, super-admins would get the same update. Thus one can see here an example of inheritance, in that super-admin roles inherit all the properties of admin roles and extend them. Note that for most part of the site, admins are interchangeable with super-admins (meaning a super-admin user can easily be used in place of an admin user, but not vice-versa in general).
I guess an egg shell can be consider the encapsulation and the contents the abstraction. The shell protects the information. You cant have the contents of an egg without the shell.,,LOL
If you have seen important TV machine, TV connections and TV color tube is hidden inside the TV case which is not been exposed for viewers like us and exposed only neccessary things of a TV like TV Channel keys, TV volume keys, ON/OFF switch, Cable Switch and TV remote control for viewers to use it.This means TV machine, TV connections and TV color tube is an unwanted data and not needed for viewers to see is been hidden from outside the world
So encapsulation means hiding the important features of a class which is not been needed to be exposed outside of a class and exposing only necessary things of a class.
Here hidden part of a class acts like Encapsulation and exposed part of a class acts like Abstraction.
Just think of Abstraction as hiding the keypad and display screen details,
Encapsulation as hiding the internal circuitry that binds them.
Abstration which hide internal detail to outside world for example you create a class(like calculator one of the class) but for end use you provide object of class ,With the help of object they will play and perform operation ,He does't aware what type of mechanism use internally .Object of class in abstract form .
Encapsulation is the technique of making the fields in a class private and providing access to the fields via public methods. If a field is declared private, it cannot be accessed by anyone outside the class, thereby hiding the fields within the class. For this reason, encapsulation is also referred to as data hiding.For example class calculator which contain private methods getAdd,getMultiply .
Mybe above answer will help you to understand the concept .
Abstraction
It is used to manage complexities of OOPs. By using this property we can provide essential features of an object to the user without including its background explanations. For example, when sending message to a friend we simply write the message, say "hiiii" and press "send" and the message gets delivered to its destination (her,friend). Here we see abstraction at work, ie we are less concerned with the internal working of mobile that is responsible for sending and receiving message
Abstraction
We use many abstractions in our day-to-day lives.Consider a car.Most of us have an abstract view of how a car works.We know how to interact with it to get it to do what we want it to do: we put in gas, turn a key, press some pedals, and so on. But we don't necessarily understand what is going on inside the car to make it move and we don't need to.
Millions of us use cars everyday without understanding the details of how they work.Abstraction helps us get to school or work!
A program can be designed as a set of interacting abstractions. In Java, these abstractions are captured in classes. The creator of a class obviusly has to know its interface, just as the driver of a car can use the vehicle without knowing how the engine works.
Encapsulation
Consider a Banking system.Banking system have properties like account no,account type,balance ..etc. If someone is trying to change the balance of the account,attempt can be successful if there is no encapsulation.
Therefore encapsulation allows class to have complete control over their properties.
Let me explain both abstraction and encapsulation with the help of the example given by you about the mobile phone.
Abstraction
The inner working on the mobile phone is hidden from the user. The user is interacting with the mobile through screen/buttons. This is equivalent to interacting with the class through an object. Here class is the mobile and the object is the screen/buttons.
Encapsulation
In a mobile phone, we can see that the battery, CPU, RAM, Camera and so on are contained together inside a box/container. This is similar to how class encapsulates all its methods and variables. The methods and variables are contained inside the class.
Also, you can't access the inner components of the mobile phone right? You need special screwdrivers for that. The components inside the mobile phone are secured. Similarly, we can secure the components or variables inside a class. We secure it with private access modifiers. Private access modifiers are the containers of the mobile phone. We can access the private fields with the help of setters and getters. These getters and setters are like special screwdrivers.
I'm currently making a client-client approach on some simulation with objective-c with two computers (mac1 and mac2).
I have a class Client, and every computer has a instance of the "Client" on it (client1,client2). I expect that both clients will be synchronized: they will both be equal apart from memory locations.
When a user presses a key on mac1, I want both client1 and client2 to receive a given method from class Client (so that they are synchronized, i.e. they are the same apart from it's memory location on each mac).
To this approach, my current idea is to make 2 methods:
- (void) sendSelector:(Client*)toClient,...;
- (void) receiveSelector:(Client*)fromClient,...;
sendSelector: uses NSStringFromSelector() to transform the method to a NSString, and send it over the network (let's not worry about sending strings over net now).
On the other hand, receiveSelector: uses NSSelectorFromString() to transform a NSString back to a selector.
My first question/issue is: to what extent is this approach "standard" on networking with objective-c?
My second question:
And the method's arguments? Is there any way of "packing" a given class instance and send it over the network? I understand the pointer's problem when packing, but every instance on my program as an unique identity, so that should be no problem since both clients will know how to retrieve the object from its identity.
Thanks for your help
Let me address your second question first:
And the method's arguments? Is there any way of "packing" a given
class instance and send it over the network?
Many Cocoa classes implement/adopt the NSCoding #protocol. This means they support some default implementation for serializing to a byte stream, which you could then send over the network. You would be well advised to use the NSCoding approach unless it's fundamentally not suited to your needs for some reason. (i.e. use the highest level of abstraction that gets the job done)
Now for the more philosophical side of your first question; I'll rephrase your question as "is it a good approach to use serialized method invocations as a means of communication between two clients over a network?"
First, you should know that Objective-C has a not-often-used-any-more, but reasonably complete, implementation for handling remote invocations between machines with a high level of abstraction. It was called Distributed Objects. Apple appears to be shoving it under the rug to some degree (with good reason -- keep reading), but I was able to find an old cached copy of the Distributed Objects Programming Topics guide. You may find it informative. AFAIK, all the underpinnings of Distributed Objects still ship in the Objective-C runtime/frameworks, so if you wanted to use it, if only to prototype, you probably could.
I can't speculate as to the exact reasons that you can't seem to find this document on developer.apple.com these days, but I think it's fair to say that, in general, you don't want to be using a remote invocation approach like this in production, or over insecure network channels (for instance: over the Internet.) It's a huge potential attack vector. Just think of it: If I can modify, or spoof, your network messages, I can induce your client application to call arbitrary selectors with arbitrary arguments. It's not hard to see how this could go very wrong.
At a high level, let me recommend coming up with some sort of protocol for your application, with some arbitrary wire format (another person mentioned JSON -- It's got a lot of support these days -- but using NSCoding will probably bootstrap you the quickest), and when your client receives such a message, it should read the message as data and make a decision about what action to take, without actually deriving at runtime what is, in effect, code from the message itself.
From a "getting things done" perspective, I like to share a maxim I learned a while ago: "Make it work; Make it work right; Make it work fast. In that order."
For prototyping, maybe you don't care about security. Maybe when you're just trying to "make it work" you use Distributed Objects, or maybe you roll your own remote invocation protocol, as it appears you've been thinking of doing. Just remember: you really need to "make it work right" before releasing it into the wild, or those decisions you made for prototyping expedience could cost you dearly. The best approach here will be to create a class or group of classes that abstracts away the network protocol and wire format from the rest of your code, so you can swap out networking implementations later without having to touch all your code.
One more suggestion: I read in your initial question a desire to 'keep an object (or perhaps an object graph) in sync across multiple clients.' This is a complex topic, but you may wish to employ a "Command Pattern" (see the Gang of Four book, or any number of other treatments in the wild.) Taking such an approach may also inherently bring structure to your networking protocol. In other words, once you've broken down all your model mutation operations into "commands" maybe your protocol is as simple as serializing those commands using NSCoding and shipping them over the wire to the other client and executing them again there.
Hopefully this helps, or at least gives you some starting points and things to consider.
These days it would seem that the most standard way is to package everything up on JSON.
I'll be as direct as I can concerning this problem, because there must be something I'm totally missing coming from a structured programming background.
Say I have a Player class. This Player class does things like changing its position in a game world. I call this method warp() which takes a Position class instance as a parameter to modify the internal position of the Player. This makes total sense to me in OO terms because I'm asking the player "to do" something.
The issue comes when I need to do other things in addition to just modifying the players position. For example, say I need to send that warp event to other players in an online game. Should that code also be within Player's warp() method? If not, then I would imagine declaring some kind of secondary method within say the Server class like warpPlayer(player, position). Doing this seems to reduce everything a player does to itself as a series of getters and setters, or am I just wrong here? Is this something that's totally normal? I've read countless times that a class that exposes everything as a series of getters/setters indicates a pretty poor abstraction (being used as a data structure instead of a class).
The same problem comes when you need to persist data, saving it to a file. Since "saving" a player to a file is at a different level of abstraction than the Player class, does it make sense to have a save() method within the player class? If not, declaring it externally like savePlayer(player) means that the savePlayer method would need a way to get every piece of data it needs out of the Player class, which ends up exposing the entire private implementation of the class.
Because OOP is the design methodology most used today (I assume?), there's got to be something I'm missing concerning these issues. I've discussed it with my peers who also do light development, and they too have also had these exact same issues with OOP. Maybe it's just that structured programming background that keeps us from understanding the full benefits of OOP as something more than providing methods to set and get private data so that it's changed and retrieved from one place.
Thanks in advance, and hopefully I don't sound too much like an idiot. For those who really need to know the languages involved with this design, it's Java on the server side and ActionScript 3 on the client side.
I advise you not to fear the fact, that player will be a class of getters and setters. What is object anyway? It's compilation of attributes and behaviours. In fact the more simple your classes are, the more benefits of an OOP you'll get in the development process.
I would breakdown your tasks/features into classes like that:
Player:
has hitpoints attribute
has position attribute
can walkTo(position), firing "walk" events
can healUp(hitpoints)
can takeDamage(hitpoints), firing "isHurt" event
can be checked for still living, like isAlive() method
Fighter extends Player (you should be able to cast Player to Fighter, when it's needed) :
has strength and other fighting params to calculate damage
can attack() firing "attack" event
World keeps track of all players:
listens to "walk" events (and prevents illegal movements)
listents to "isHurt" events (and checks if they are still alive)
Battle handles battles between two fighters:
constructor with two fighters as parameters (you only want to construct battle between players that are really fighting with each other)
listens to "attack" events from both players, calculates damage, and executes takeDamage method of the defending player
PlayerPersister extends AbstractPersister:
saves player's state in database
restores player's state from database
Of course, you game's breakdown will be much more complicated, but i hope this helps you to start thinking of problems in "more OOP" way :)
Don't worry too much about the Player class being a bunch of setters and getters. The Player class is a model class, and model classes tend to be like that. It's important that your model classes are small and clean, because they will be reused all over the program.
I think you should use the warpPlayer(player, position) approach you suggested. It keeps the Player class clean. If you don't want to pass the player into a function, maybe you could have a PlayerController class that contains a Player object and a warp(Position p) method. That way you can add event posting to the controller, and keep it out of the model.
As for saving the player, I'd do it by making Player implement some sort of serialisation interface. The player class is responsible for serializing and unserializing itself, and some other class would be responsible for writing the serialised data to/from a file.
I would probably consider having a Game object that keeps track of the player object. So you can do something like game.WarpPlayerTo(WarpLocations.Forest); If there are multiple players, maybe pass a player object or guid with it. I feel you can still keep it OO, and a game object would solve most of your issues I think.
The problems you are describing don't belong just to game design, but to software architecture in general. The common approach is to have a Dependency Injection (DI) and Inversion of Control (IoC) mechanisms. In short what you are trying to achieve is to be able to access a local Service of sorts from your objects, in order for example to propagate some event (e.g warp), log, etc.
Inversion of control means in short that instead of creating your objects directly, you tell some service to create them for you, that service in turn uses dependency injection to inform the objects about the services that they depend on.
If you are sharing data between different PCs for multiplayer, then a core function of the program is holding and synchronising that piece of state between the PCs. If you keep these values scattered about in many different classes, it will be difficult to synchronise.
In that case, I would advise that you design the data that needs to be synchronised between all the clients, and store that in a single class (e.g. GameState). This object will handle all the synchronisation between different PCs as well as allowing your local code to request changes to the data. It will then "drive" the game objects (Player, EnemyTank, etc) from its own state. [edit: the reason for this is that keeping this state as small as possible and transferring it efficiently between the clients will be a key part of your design. By keeping it all in one place it makes it much easier to do this, and encourages you to only put the absolute essentials in that class so that your comms don't become bloated with unnecessary data]
If you're not doing multiplayer, and you find that changing the player's position needs to update multiple objects (e.g. you want the camera to know that the player has moved so that it can follow him), then a good approach is to make the player responsible for its own position, but raise events/messages that other objects can subscribe/listen to in order to know when the player's position changes. So you move the player, and the camera gets a callback telling it that the player's position has been updated.
Another approach for this would be that the camera simply reads the player's position every frame in order to updaet itself - but this isn't as loosely coupled and flexible as using events.
Sometimes the trick to OOP is understanding what is an object, and what is functionality of an object. I think its often pretty easy for us to conceptually latch onto objects like Player, Monster, Item, etc as the "objects" in the system and then we need to create objects like Environment, Transporter, etc to link those objects together and it can get out-of-control depending on how the concepts work together, and what we need to accomplish.
The really good engineers I have worked with in the past have had a way of seeing systems as collections of objects. Sometimes in one system they would be business objects (like item, invoice, etc) and sometimes they would be objects that encapsulated processing logic (DyeInjectionProcessor, PersistanceManager) which cut across several operations and "objects" in the system. In both cases the metaphors worked for that particular system and made the overall process easier to implement, describe, and maintain.
The real power of OOP is in making things easier to express and manage in large complex systems. These are the OOP principles to target, and not worry as much whether it fits a rigid object hierarchy.
I havent worked in game design, so perhaps this advice will not work as well, in the systems I do work on and develop it has been a very beneficial change to think of OOP in terms of simplification and encapsulation rather than 1 real world object to 1 OOP class.
I'd like to expand on GrayWizardx's last paragraph to say that not all objects need to have the same level of complexity. It may very well fit your design to have objects that are simple collections of get/set properties. On the other hand, it is important to remember that objects can represent tasks or collections of tasks rather than real-world entities.
For example, a player object might not be responsible for moving the player, but instead representing its position and current state. A PlayerMovement object might contain logic for changing a player's position on screen or within the game world.
Before I start simply repeating what's already been said, I'll point towards the SOLID principles of OOP design (Aviad P. already mentioned two of them). They might provide some high-level guidelines for creating a good object model for a game.