This question already has answers here:
Abstraction VS Information Hiding VS Encapsulation
(22 answers)
Difference between abstraction and encapsulation?
(40 answers)
Closed 2 months ago.
Can somebody explain to me the main differences between the principles of encapsulation and abstraction in objected-oriented programming (if possible with examples).
Sample:
// NO ABSTRACTION, NO ENCAPSULATION
const int catLegs = 4;
const int spiderLegs = 8;
Leg[] catLegs;
Leg[] spiderLegs;
void MakeCatRun(Distance b) { for (int i=0; i<catLegs; ++i) catLegs[i] += b; }
void MakeSpiderRun(Distance b) { for (int i=0; i<spiderLegs; ++i) spiderLegs[i] += b; }
Encapsulation:
// ENCAPSULATION
class Cat
{
Leg[] legs;
int nLegs;
public void Run(Distance b) { for (int i=0; i < nLegs; ++i) leg[i] += b; }
}
class Spider
{
Leg[] legs;
int nLegs;
public void Run(Distance b) { for (int i=0; i < nLegs; ++i) leg[i] += b; }
}
Abstraction:
// ABSTRACTION
class LivingBeing
{
Leg[] legs;
int nLegs;
public void Run(Distance b) { for (int i=0; i < nLegs; ++i) leg[i] += b; }
}
class Cat: LivingBeing { }
class Spider: LivingBeing { }
Abstraction is that quality that we just do not bother about unnecessary internal mechanisms (implementations) and can deal with a system/object, looking in to the essentialities.
Eg: While applying brakes on a car you just don't care if it has got air-brake or hydraulic-brake. Abstraction comes in the form of a pedal-push here.
Encapsulation is something that makes the above (abstraction) possible by packing (encapsulating) details of implementation within a container (hiding away breaking mechanisms and tiny components from your eyesight or physical contact, in the above case).
So, Encapsulation in effect provides Abstraction!
If you look around, you can see it everywhere around you in real world. Also it is there in programming- If Someone provides you a class to Sort list of integers, you don't really need to bother about the sorting algorithm (bubble sort/Quick Sort) it uses, The abstraction makes it possible that you 'pass the list of integers' to the method; that is it.
class Sorter
{
public List<Integer> Sort(List<Integer>)//Only this method is seen outside
{
String pattrenName=this.AdvancedPatternFinder();
this.Advancedsorter(pattenName);
//Return sorted list
}
private String AdvancedPatternFinder(){}//NOT seen from outside
private void Advancedsorter(String pattrenName){}//NOT seen from outside
}
See the below animation to understand how a neat abstraction is provided by encapsulating internal details inside!
image courtesy:this blog
Encapsulation means that object's internal state (data) can be modified only by its public methods (public interface):
class Encapsulated {
private int data;
public int getData() { return data; }
public void setData(int d) { data = d; }
}
Abstraction means that you can abstract from concrete implementations, for example:
abstract class Container {
int getSize();
}
class LinkedList extends Container {
int getSize() { /* return the size */ }
}
class Vector extends Container {
int getSize() { /* ... */ }
}
If you will be using the Container abstract class in all your code instead of Vector or LinkedList, you will be able to switch the concrete implementation of Container (Vector/LinkedList in this case) without changing any of your code, thus abstracting yourself from the implementation.
The two concepts are distinct, but closely related and are often found together.
Abstraction is hiding of non-essential details, usually termed implementation details. For example, to read data from a stream, most environments have the concept of an InputStream. It provides a ReadBytes() method to fetch more bytes from the stream. How it does this is abstracted away - it could be reading from a file, using the OS file APIs, or reading from a socket, from SSH or anything else that can be presented as a stream of bytes. The InputStream class is said to be an abstraction.
Each implementation of InputStream codes how the bytes are read. For example, a FileInputStream reads bytes from a file, and maintains the current offset into the file as a private data member. Code external to the class does not have free access to read or write this variable directly - doing so might lead to incorrect results, such as part of the stream being skipped, or re-read. This is especially important in multi-threaded scenarios, when changes to the variable needs to be carefully controlled. Instead of giving unfettered access, the class uses the offset internally (by declaring it private), and gives external code only indirect access, such as via a method GetCurrentOffset(), and methods Seek(int offset). The offset variable is then encapsulated by the FileInputStream class.
Related
Here's a bare minimum pseodo-code of what I use:
class A{
//other variables
B b;
void delayedPartnerInit(B b){
this.b=b;
}
}
class B{
//some other variables
A a;
void delayedPartnerInit(A a){
this.a=a;
}
}
I could make it into a single class but certain members(not shown here) of A are needed to exist before data about B. In other words, objects of A and B are instanced at different times but need reference of each other's variables once both set of variables are available.
The question is there a better way to do this? Am I missing some basic concept of programming?
Though I am currently working on C#, I have had this thought many times before when working with other languages too.
Update: I am using this in Unity game engine where B is Unity C# script. Since Unity doesn't allow us create scripts without adding it to something I need 2 classes. I get certain data(A's data) earliar which needs processing.
Didn't mention this earlier because I asked it as a generic question.
Note before closing as duplicate: I checked similar questions but found only specific questions that caused issues to authors who tried to do what I am doing. My question is whether it is a bad practice.
Tightly coupled classes are generally bad practice:
Changes in one class lead to changes in another.
You cannot test one of classes without creating (or mocking) another one. Which in your case creates circular dependency.
Both classes depend on each other's implementations, not abstractions.
Harder for other persons (or yourself half a year later) to understand and reason about first class logic without inspecting second class as well.
Since Unity doesn't allow us create scripts without adding it to something I need 2 classes. I get certain data(A's data) earliar which needs processing
MVC pattern for Unity provides useful trick for decoupling monobehaviours:
interface ISomeObjectView {
event Action OnUpdate;
event Action Destroyed;
event Action TriggerEntered;
void SetTransform(Vector3 position, Quaternion rotation);
void AddForce(Vector3 force);
// Other methods or events you need to expose:
// MouseOver, OnFixedUpdate, Move() or SetScale(), ...
}
MonoBehaviour itself does not contain any logic, it simply invokes events and uses incoming values:
public void SetTransform(Vector3 position, Quaternion rotation)
{
// Params validation
transform.rotation = rotation;
transform.position = position;
}
private void Update()
=> OnUpdate?.Invoke();
MonoBehaviour logic must be moved to your data class or new controller class. Now your data class simply links itself to provided interface events and methods without circular dependencies. Monobehaviour does not require any references to other classes, it simply provides methods to manipulate itself and events to catch input.
This trick helps in several ways:
MonoBehaviour doesn't depend on anything and doesn't require any references to other classes.
Your data/logic classes doesn't require ant special knowledge about monobehaviours, only provided interface.
You can have several implementations for interface, switching different views depending on situation.
Easy to test, easy to mock.
You can move all the "Unity stuff" inside MonoBehaviour and write all related classes on pure C#. If you want to.
Please note that using event Action is not conventional way to deal with events! I think it's very convenient, but I'd suggest to use conventional EventHandler (UnityEvents is another option that might suit your needs).
Update: an example of simple MVC.
Consider the following Player controller:
[Serializable]
public class PlayerInfo {
// Values configurable via inspector
[SerializeField] private float speed = 1.5f;
[SerializeField] private float jumpHeight = 5;
[SerializeField] private float damage = 15;
[SerializeField] private Player playerPrefab;
public float Speed => speed;
public float JumpHeight => jumpHeight ;
public float Damage => damage;
private Player playerInstance;
public void InitializePlayer() {
playerInstance = Instantiate(playerPrefab);
playerInstance.Info = this;
}
public void TeleportTo(Vector3 newPosition) {
playerInstance.transform.position = newPosition;
}
}
public class Player : MonoBehaviour {
public PlayerInfo Info { get; set; }
private Rigidbody rb;
private void Awake() {
rb = GetComponent<Rigidbody>();
}
private void Update() {
if (Input.GetButtonDown("Jump")
rb.AddForce(Vector3.up * info.JumpHeight);
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
rb.AddForce(movement * info.Speed);
}
private void OnTriggerEnter(Collider other) {
var enemy = other.GetComponent<Enemy>();
if (enemy != null)
enemy.TakeHit(info.Damage);
}
}
There you go. PlayerInfo is created before Player. PlayerInfo references Player and Player references PlayerInfo. Player is used to move gameobject and attack enemies, PlayerInfo contains required info. What can we do here?
First, Rewrite MonoBehaviour without any logic:
public class PlayerView : MonoBehaviour {
private Rigidbody rb;
// Events for future subscription.
public event Action OnUpdate;
public event TriggerEntered<Collider>;
// Simple initialization of required components.
private void Awake() {
rb = GetComponent<Rigidbody>();
}
// Unity methods doing nothing but invoking events.
private void Update() {
OnUpdate?.Invoke();
}
private void OnTriggerEnter(Collider other) {
TriggerEntered?.Invoke(other);
}
// We still need a method to move our player, right?
public void Move(Vector3 direction) {
rb.AddForce(direction);
}
public void SetPosition(Vector3 position) {
transform.position = position;
}
}
Now you need class containing data about player:
[Serializable]
public class PlayerModel {
[SerializeField] private float speed = 1.5f;
[SerializeField] private float jumpHeight = 5;
[SerializeField] private float damage = 15;
public float Speed => speed;
public float JumpHeight => jumpHeight ;
public float Damage => damage;
}
Now we need a way to tie those two together:
public class PlayerController {
private readonly PlayerModel model;
private readonly PlayerView view;
public PlayerController(PlayerModel model, PlayerView view) {
// Validate values here.
this.model = model;
this.view = view;
// Linking logic to events.
view.OnUpdate += Move;
view.TriggerEntered += Attack;
}
// Actual logic moved here.
private void Move() {
Vector3 movement = Vector3.zero;
if (Input.GetButtonDown("Jump")
movement += Vector3.up * model.JumpHeight;
movement += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * model.Speed;
view.Move(movement);
}
private void Attack(Collider other) {
var enemy = other.GetComponent<Enemy>();
if (enemy != null)
enemy.TakeHit(model.Damage);
}
// Method from PlayerInfo to set player position without actual movements.
public void MoveTo(Vector3 position) {
view.SetPosition(position);
}
}
Now you have 3 classes instead of 2, but model and view classes are very simple and do not require any dependencies. All the work is done by Controller class, which receives other two pieces and ties them together.
It becomes even better when interfaces are introduced in addition to classes: IPlayerModel, IPlayerView, IPlayerController.
You might think that it would be easier to create single class instead of three linked classes, but in the long run you will thank yourself for using this pattern: view and model are extremely simple, easy to read, easy to check for errors, easy to expand with new functionality. Single class, on the other hand, will quickly grow to hundreds of lines and become a nightmare to test and expand.
I strongly recommend this article with more complicated examples of MVC.
I have an interface and two data sources that populate concrete instances of objects that implement the interface. The interface exposes methods that only one of the two instances can satisfy in a meaningful way.
public interface IFoo {
public int getValueA();
public int getValueB();
}
public FooFromFile implements IFoo {
int a;
int b;
...
public int getValueA() {
return a;
}
public int getValueB() {
return b;
}
}
public FooFromNetwork implements IFoo {
int a;
...
public int getValueA() {
return a;
}
public int getValueB() {
return 0; // return 0 because FooFromNetwork never gets value b.
}
}
Every code base I've worked on has code like this and I find it usually stems from a desire to apply 'is-a' relationships where something else may be more appropriate. I have some time to refactor the code base on which I am currently working. What would be some good modeling solutions for situations like this? The actual code is much more complicated than this but solving the toy issue here, with a robust pattern that scales, would go a long way.
The problem described here "is a" (pun intended) violation of the Liskov Substitution Principle. There are many solutions to LSP violations, but nothing is one-size-fits-all. For example, depending on context you may choose to favor composition over inheritance or apply interface segregation.
I am facing a design problem. This must only be solved by applying oops concepts. I am describing the problem below.
Problem: Suppose You have a class called X . It has two Paid (Chargeable) methods like m, n. Their may be many consumers classes of these methods. Someone pays for m, someone pays for n and someone pays for both m, n.
Now I have to design my X class in such a way that consumers can only see that method for which they make payment. How can we do this via OOPS concepts? I can make appropriate changes in my X class to achieve this design. Sample class is written below.
class X { // service class
public m(){ // do some stuff
}
public n(){ // do some stuff
}
}
Create 3 interfaces: one containing the m method, one containing n and a third containing both (the third interface can extend the two others). Then make your class X implement those interfaces.
You will then be able to expose the appropriate interface to your consumers, depending on their needs, while still using the same X class.
interface M { // exposed to customers paying for m
void m();
}
interface N { // exposed to customers paying for n
void n();
}
interface Mn extends M, N {} // exposed to customers paying for both
class X implements Mn {
#Override
public m(){ // do some stuff
}
#Override
public n(){ // do some stuff
}
}
I think you are not taking advantage of the class state. Class can store information in its instance fields about the user, and change its behavior accordingly.
One possible option would be:
class Payment {
int paymentType = 0; // fill with constructor for i.e.
public pay(int sum){
// some common behavior
switch(this.paymentType){
case 1:
// pay 1 logic
break;
case 2:
// pay 2 logic
break;
}
// some other common behavior
}
}
In another design you might use the Strategy pattern to have family of decoupled algorithms.
In the above code I assumed we are talking about some logically related code. If the code has nothing in common, you might even split it into other classes.
Update: I wouldn't advice on using it, but you can implement the Template Method pattern. The problem is you are going to overuse inheritance.
abstract class Payment {
public Pay(int sum){
// some common code
this.doPay(sum);
}
abstract protected doPay(int sum);
}
class PaymentOne : Payment {
protected doPay(int sum){
// pay 1 logic
}
}
class PaymentTwo : Payment {
protected doPay(int sum){
// pay 2 logic
}
}
You'd better use polymorphism concept
As example, based on assumption that m and n has different types:
class X{ // service class
public Pay(NType n){ // do some stuff
}
public Pay(MType m){ // do some stuff
}
public Pay(NType n, MType m){ // do some stuff
Pay(n);
Pay(m);
}
}
I am new to OOP. Though I understand what polymorphism is, but I can't get the real use of it. I can have functions with different name. Why should I try to implement polymorphism in my application.
Classic answer: Imagine a base class Shape. It exposes a GetArea method. Imagine a Square class and a Rectangle class, and a Circle class. Instead of creating separate GetSquareArea, GetRectangleArea and GetCircleArea methods, you get to implement just one method in each of the derived classes. You don't have to know which exact subclass of Shape you use, you just call GetArea and you get your result, independent of which concrete type is it.
Have a look at this code:
#include <iostream>
using namespace std;
class Shape
{
public:
virtual float GetArea() = 0;
};
class Rectangle : public Shape
{
public:
Rectangle(float a) { this->a = a; }
float GetArea() { return a * a; }
private:
float a;
};
class Circle : public Shape
{
public:
Circle(float r) { this->r = r; }
float GetArea() { return 3.14f * r * r; }
private:
float r;
};
int main()
{
Shape *a = new Circle(1.0f);
Shape *b = new Rectangle(1.0f);
cout << a->GetArea() << endl;
cout << b->GetArea() << endl;
}
An important thing to notice here is - you don't have to know the exact type of the class you're using, just the base type, and you will get the right result. This is very useful in more complex systems as well.
Have fun learning!
Have you ever added two integers with +, and then later added an integer to a floating-point number with +?
Have you ever logged x.toString() to help you debug something?
I think you probably already appreciate polymorphism, just without knowing the name.
In a strictly typed language, polymorphism is important in order to have a list/collection/array of objects of different types. This is because lists/arrays are themselves typed to contain only objects of the correct type.
Imagine for example we have the following:
// the following is pseudocode M'kay:
class apple;
class banana;
class kitchenKnife;
apple foo;
banana bar;
kitchenKnife bat;
apple *shoppingList = [foo, bar, bat]; // this is illegal because bar and bat is
// not of type apple.
To solve this:
class groceries;
class apple inherits groceries;
class banana inherits groceries;
class kitchenKnife inherits groceries;
apple foo;
banana bar;
kitchenKnife bat;
groceries *shoppingList = [foo, bar, bat]; // this is OK
Also it makes processing the list of items more straightforward. Say for example all groceries implements the method price(), processing this is easy:
int total = 0;
foreach (item in shoppingList) {
total += item.price();
}
These two features are the core of what polymorphism does.
Advantage of polymorphism is client code doesn't need to care about the actual implementation of a method.
Take look at the following example.
Here CarBuilder doesn't know anything about ProduceCar().Once it is given a list of cars (CarsToProduceList) it will produce all the necessary cars accordingly.
class CarBase
{
public virtual void ProduceCar()
{
Console.WriteLine("don't know how to produce");
}
}
class CarToyota : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Toyota Car ");
}
}
class CarBmw : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Bmw Car");
}
}
class CarUnknown : CarBase { }
class CarBuilder
{
public List<CarBase> CarsToProduceList { get; set; }
public void ProduceCars()
{
if (null != CarsToProduceList)
{
foreach (CarBase car in CarsToProduceList)
{
car.ProduceCar();// doesn't know how to produce
}
}
}
}
class Program
{
static void Main(string[] args)
{
CarBuilder carbuilder = new CarBuilder();
carbuilder.CarsToProduceList = new List<CarBase>() { new CarBmw(), new CarToyota(), new CarUnknown() };
carbuilder.ProduceCars();
}
}
Polymorphism is the foundation of Object Oriented Programming. It means that one object can be have as another project. So how does on object can become other, its possible through following
Inheritance
Overriding/Implementing parent Class behavior
Runtime Object binding
One of the main advantage of it is switch implementations. Lets say you are coding an application which needs to talk to a database. And you happen to define a class which does this database operation for you and its expected to do certain operations such as Add, Delete, Modify. You know that database can be implemented in many ways, it could be talking to file system or a RDBM server such as MySQL etc. So you as programmer, would define an interface that you could use, such as...
public interface DBOperation {
public void addEmployee(Employee newEmployee);
public void modifyEmployee(int id, Employee newInfo);
public void deleteEmployee(int id);
}
Now you may have multiple implementations, lets say we have one for RDBMS and other for direct file-system
public class DBOperation_RDBMS implements DBOperation
// implements DBOperation above stating that you intend to implement all
// methods in DBOperation
public void addEmployee(Employee newEmployee) {
// here I would get JDBC (Java's Interface to RDBMS) handle
// add an entry into database table.
}
public void modifyEmployee(int id, Employee newInfo) {
// here I use JDBC handle to modify employee, and id to index to employee
}
public void deleteEmployee(int id) {
// here I would use JDBC handle to delete an entry
}
}
Lets have File System database implementation
public class DBOperation_FileSystem implements DBOperation
public void addEmployee(Employee newEmployee) {
// here I would Create a file and add a Employee record in to it
}
public void modifyEmployee(int id, Employee newInfo) {
// here I would open file, search for record and change values
}
public void deleteEmployee(int id) {
// here I search entry by id, and delete the record
}
}
Lets see how main can switch between the two
public class Main {
public static void main(String[] args) throws Exception {
Employee emp = new Employee();
... set employee information
DBOperation dboper = null;
// declare your db operation object, not there is no instance
// associated with it
if(args[0].equals("use_rdbms")) {
dboper = new DBOperation_RDBMS();
// here conditionally, i.e when first argument to program is
// use_rdbms, we instantiate RDBM implementation and associate
// with variable dboper, which delcared as DBOperation.
// this is where runtime binding of polymorphism kicks in
// JVM is allowing this assignment because DBOperation_RDBMS
// has a "is a" relationship with DBOperation.
} else if(args[0].equals("use_fs")) {
dboper = new DBOperation_FileSystem();
// similarly here conditionally we assign a different instance.
} else {
throw new RuntimeException("Dont know which implemnation to use");
}
dboper.addEmployee(emp);
// now dboper is refering to one of the implementation
// based on the if conditions above
// by this point JVM knows dboper variable is associated with
// 'a' implemenation, and it will call appropriate method
}
}
You can use polymorphism concept in many places, one praticle example would be: lets you are writing image decorer, and you need to support the whole bunch of images such as jpg, tif, png etc. So your application will define an interface and work on it directly. And you would have some runtime binding of various implementations for each of jpg, tif, pgn etc.
One other important use is, if you are using java, most of the time you would work on List interface, so that you can use ArrayList today or some other interface as your application grows or its needs change.
Polymorphism allows you to write code that uses objects. You can then later create new classes that your existing code can use with no modification.
For example, suppose you have a function Lib2Groc(vehicle) that directs a vehicle from the library to the grocery store. It needs to tell vehicles to turn left, so it can call TurnLeft() on the vehicle object among other things. Then if someone later invents a new vehicle, like a hovercraft, it can be used by Lib2Groc with no modification.
I guess sometimes objects are dynamically called. You are not sure whether the object would be a triangle, square etc in a classic shape poly. example.
So, to leave all such things behind, we just call the function of derived class and assume the one of the dynamic class will be called.
You wouldn't care if its a sqaure, triangle or rectangle. You just care about the area. Hence the getArea method will be called depending upon the dynamic object passed.
One of the most significant benefit that you get from polymorphic operations is ability to expand.
You can use same operations and not changing existing interfaces and implementations only because you faced necessity for some new stuff.
All that we want from polymorphism - is simplify our design decision and make our design more extensible and elegant.
You should also draw attention to Open-Closed Principle (http://en.wikipedia.org/wiki/Open/closed_principle) and for SOLID (http://en.wikipedia.org/wiki/Solid_%28Object_Oriented_Design%29) that can help you to understand key OO principles.
P.S. I think you are talking about "Dynamic polymorphism" (http://en.wikipedia.org/wiki/Dynamic_polymorphism), because there are such thing like "Static polymorphism" (http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism).
You don't need polymorphism.
Until you do.
Then its friggen awesome.
Simple answer that you'll deal with lots of times:
Somebody needs to go through a collection of stuff. Let's say they ask for a collection of type MySpecializedCollectionOfAwesome. But you've been dealing with your instances of Awesome as List. So, now, you're going to have to create an instance of MSCOA and fill it with every instance of Awesome you have in your List<T>. Big pain in the butt, right?
Well, if they asked for an IEnumerable<Awesome>, you could hand them one of MANY collections of Awesome. You could hand them an array (Awesome[]) or a List (List<Awesome>) or an observable collection of Awesome or ANYTHING ELSE you keep your Awesome in that implements IEnumerable<T>.
The power of polymorphism lets you be type safe, yet be flexible enough that you can use an instance many many different ways without creating tons of code that specifically handles this type or that type.
Tabbed Applications
A good application to me is generic buttons (for all tabs) within a tabbed-application - even the browser we are using it is implementing Polymorphism as it doesn't know the tab we are using at the compile-time (within the code in other words). Its always determined at the Run-time (right now! when we are using the browser.)
How do you code special cases for objects?
For example, let's say I'm coding an rpg - there are N = 5 classes. There are N^2 relationships in a matrix that would determine if character A could attack (or use ability M on) character B (ignoring other factors for now).
How would I code this up in OOP without putting special cases all over the place?
Another way to put it is, I have something maybe
ClassA CharacterA;
ClassB CharacterB;
if ( CharacterA can do things to CharacterB )
I'm not sure what goes inside that if statement, rather it be
if ( CharacterA.CanDo( CharacterB ) )
or a metaclass
if ( Board.CanDo( CharacterA, CharacterB ) )
when the CanDo function should depend on ClassA and ClassB, or attributes/modifiers with ClassA/ClassB?
i would start with a canSee(Monster monster) or canBeSeenBy(Monster monster) method and see what happens. you may end up with a Visibilility class or end up using the http://en.wikipedia.org/wiki/Visitor_pattern. an extreme example is uncle bobs triple dispatch:
// visitor with triple dispatch. from a post to comp.object by robert martin http://www.oma.com
/*
In this case, we are actually using a triple dispatch, because we have two
types to resolve. The first dispatch is the virtual Collides function which
resolves the type of the object upon which Collides is called. The second
dispatch is the virtual Accept function which resolves the type of the
object passed into Collides. Now that we know the type of both objects, we
can call the appropriate global function to calculate the collision. This
is done by the third and final dispatch to the Visit function.
*/
interface AbstractShape
{
boolean Collides(final AbstractShape shape);
void Accept(ShapeVisitor visitor);
}
interface ShapeVisitor
{
abstract public void Visit(Rectangle rectangle);
abstract public void Visit(Triangle triangle);
}
class Rectangle implements AbstractShape
{
public boolean Collides(final AbstractShape shape)
{
RectangleVisitor visitor=new RectangleVisitor(this);
shape.Accept(visitor);
return visitor.result();
}
public void Accept(ShapeVisitor visitor)
{ visitor.Visit(this); } // visit Rectangle
}
class Triangle implements AbstractShape
{
public boolean Collides(final AbstractShape shape)
{
TriangleVisitor visitor=new TriangleVisitor(this);
shape.Accept(visitor);
return visitor.result();
}
public void Accept(ShapeVisitor visitor)
{ visitor.Visit(this); } // visit Triangle
}
class collision
{ // first dispatch
static boolean Collides(final Triangle t,final Triangle t2) { return true; }
static boolean Collides(final Rectangle r,final Triangle t) { return true; }
static boolean Collides(final Rectangle r,final Rectangle r2) { return true; }
}
// visitors.
class TriangleVisitor implements ShapeVisitor
{
TriangleVisitor(final Triangle triangle)
{ this.triangle=triangle; }
public void Visit(Rectangle rectangle)
{ result=collision.Collides(rectangle,triangle); }
public void Visit(Triangle triangle)
{ result=collision.Collides(triangle,this.triangle); }
boolean result() {return result; }
private boolean result=false;
private final Triangle triangle;
}
class RectangleVisitor implements ShapeVisitor
{
RectangleVisitor(final Rectangle rectangle)
{ this.rectangle=rectangle; }
public void Visit(Rectangle rectangle)
{ result=collision.Collides(rectangle,this.rectangle); }
public void Visit(Triangle triangle)
{ result=collision.Collides(rectangle,triangle); }
boolean result() {return result; }
private boolean result=false;
private final Rectangle rectangle;
}
public class MartinsVisitor
{
public static void main (String[] args)
{
Rectangle rectangle=new Rectangle();
ShapeVisitor visitor=new RectangleVisitor(rectangle);
AbstractShape shape=new Triangle();
shape.Accept(visitor);
}
}
Steve Yegge has an awesome blog post about the Properties pattern that you could use handle this. In fact, he wrote an RPG using it!
http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html
You might say player1 is a type1 and type1s can attack type2s and player2 is a type2, so unless there is some "override" on the specific player1, player1 can attack player2.
This enables very robust and extensible behavior.
What is the definition of "see"? If they occupy the same square? If so, this will be answered in how you implement collision detection (or whatever in this case) rather then OOP relationships between characters. Without knowing more information, I would approach the problem in this manner (in C++/pseudo code for illustration):
class Character {
private:
matrixSquare placement;
public:
Character() {};
~Character {};
matrixSquare getLocation() { return placement;};
};
class GameBoard {
private:
//your 5 x 5 matrix here
public:
GameBoard() {};
~GameBoard() {};
boolean isOccupied(matrixSquare)
{
if (occupied)
{
//do something
return true;
}
else
{
return false;
}
}
};
The trick here is to define the relationship between your character pieces and your implementation of the playing field. After that is established you could then clarify how you determine if two characters are in the same square, adjoining squares, etc... Hope that helps.
I would say use design patterns, generally I think Observer, Mediator and Visitor patterns are quite good for managing complex inter-object relationships.
I would (assuming C++) give each class a std::string identifier, returned by a getter method on the class's instance, and use a std::map< std::pair<std::string, std::string>, ... > to encode the special cases of relationship between classes, all nice and ordered in one place. I'd also access that map exclusively through a getter function so that changing the strategy for encoding some or all of the special cases is made easy as pie. E.g.: if only a few pairs of classes out of the 25 have the "invisibility" property, the map in that case might contain only the few exceptions that do have that property (for a boolean property like this a std::set might actually be a preferable implementation, in C+_).
Some OO languages have multi-dispatch (Common Lisp and Dylan are the two that come to mind at the moment), but for all the (vast majority) of languages that lack it, this is a good approach (in some cases you'll find that a centralized map / dict is restrictive and refactor to a Dynamic Visitor design pattern or the like, but thanks to the "getter function" such refactorings will be pretty transparent to all the rest of your code).
In response to your edit of your question, you'll want to look into polymorphism. I personally would have the cando() function be a part of the Board, then, depending on the two classes passed in, the Board would call the appropriate function and return the result (of battle, of seeing, so on and so forth).
If you're doing this in java an enum/interface to go along with your Game Board would be a very clean way of approaching this problem.
I suggest you look at double dispatch pattern.
http://c2.com/cgi/wiki?DoubleDispatchExample
The above example explains how a group of printers can print a group of shapes.
http://en.wikipedia.org/wiki/Double_dispatch
The wikipedia example specifically mentions solving adaptive collision problems with this pattern.