I read the Robert Martin's article about the Interface Segregation Principle here. At the end of the article, when solving a problem with ATM UI architecture he stated:
Consider also that each different transaction that the ATM can perform is encasulated as a derivative of the class Transaction. Thus we might have classes such as DepositTransaction, WithdrawlTransaction, TransferTransaction, etc. Each of these objects issues message to the UI. For example, the DepositTransaction object calls the RequestDepositAmount member function of the UI class. Whereas the TransferTransaction object calls the RequestTransferAmount member function of UI. This corresponds to the diagram in Figure 5.
Notice that this is precicely the situation that the ISP tells us to avoid. Each of the transactions is using a portion of the UI that no other object uses. This creates the possibility that changes to one of the derivatives of Transaction will force coresponding change to the UI, thereby affecting all the other derivatives of Transaction, and every other class that depends upon the UI interface.
So we have the following situation: if one of Transaction's derivatives is changed, then UI is changed and any other class that uses UI is changed too.
Then that problem is being solved by the following changes:
This unfortunate coupling can be avoided by segregating the UI
interface into induvidual abstract base classes such as DepositUI,
WithdrawUI and TransferUI. These abstract base classes can then be
multiply inherited into the final UI abstract class. Figure6 and
Listing 6 show this model.
But next Robert Martin states that:
It is true that, whenever a new derivative of the Transaction class is
created, a coresponding base class for the abstract UI class will be
needed. Thus the UI class and all its derivatives must change.
However, these classes are not widely used. Indeed, they are probably
only used by main, or whatever process boots the system and creates
the concrete UI instance. So the impact of adding new UI base classes
is contained.
And that's the question: how is it possible that UI's changed but no other classes are changed too? After all, if some kind of TransactionX uses XUI and XUI is superclass of UI and UI is changed (because of some ZUI), then (as far as i'm concerned) compiler needs to recompile all the classes that use XUI too, because vtable (in terms of C++) or maybe some function base addresses have been changed by change of UI. Could someone make it clean for me?
if some kind of TransactionX uses XUI and XUI is superclass of UI and UI is changed, then (as far as i'm concerned) compiler needs to recompile all the classes that use XUI too
Yes but in this case, only TransactionX depends on XUI. All other TransactionY and YUI are not impacted and do not need to be recompiled.
because vtable (in terms of C++) or maybe some function base addresses have been changed by change of UI.
You would recompile main (or ui_globals.cc in the text) which is where the address to the X/Y/Z UI interfaces are obtained to be passed to the Transaction X/Y/Z instances.
this is my first post and I really did a lot of research on the topic before posting here. But now I found several possible solutions and I'm just not sure what is the proper way.
Problem
We are currently developing a local coop game that is a mix of an action game for one player and a puzzle game for the second one. Our actual problem is the input that is currently handled by a player controller that casts on every action mapping delegate received to determine if the possessed Pawn is from type PlayerA or PlayerB to then call the right function.
Let me give you a specific example:
We have two action bindings for the Button B (XBox Controller) currently called "B"
When the delegate is called we cast the possessedPlayer to check whether it shall call PlayerA->Jump or PlayerB->Blink
I'm totally unhappy with the situation that I have to cast everytime we receive an Input just to check wether I have possessed action/puzzle char
Solutions
1) Create 2 PlayerControllers and swap them by using GameMode::SwapPlayerController(Old, New)
I found this function during research but I'm not happy with creating a Player with PlayerControllerA to immediately switch it to use PlayerControllerB,
2) Shift responsibility to the Charatcer class
Another thought would be to delegate the decision making to the Character class by passing down an enum value like E_BUTTON_B from the PlayerController to the Character. We could write a macro that creates this enum based on our input mappings and then delegate the decision to a generic Character->ProcessInput(EnumValue) function. I'm also not quite happy because then the PC does not make so much sense to me.
3) Cache the possessed Pawn to avoid the cast
Another idea would have been to cache the type of the possessed Character whenever the PC possesses a Pawn. This would get rid of the cast per input delegate call.
I would be very glad for advide and any hint how you folks solve such issues in your games. Our main goals are separation of concern, good maintainability and input rebinding.
Cheers and have a nice day,
Parzival
You can create structure like this (written in C++, but this approach could be easily implemented in Blueprints as well):
class MyGameBasePlayerController : public PlayerController
{
// TODO methods common for both controllers (for example Escape key handling)
}
Now specific controllers:
class PuzzlePlayerControler : public MyGameBasePlayerController
{
UPROPERTY(BlueprintReadWrite, Transient, Category = "MyCat"
PuzzleCharacter* puzzleChar;
// TODO handle specific actions for Puzzle chararacter and control handling.
// TODO override base methods / input bindings if necesary
virtual void Possess(APawn* pawn) override;
}
Same goes for ActionPlayerCharacter.
You need to decide, how your characters will differ. If they are same, you can use something like MyGameCharacter : public PlayerCharacter (or you can use broader class PlayerPawn) and your PlayerControllers will call appropriate methods. Then your stored reference to MyGameCharacter can be stored in MyGameBasePlayerController.
Or you can use inheritance as well, so you will have PuzzleCharacter : public MyGameCharacter and ActionCharacter : MyGameCharacter with some common base implementation and extending methods or use virtual method overriding.
Depending on your final structure, you can use overriden Possess method (UE Docs) to get actual pawn instance, cast it to appropriate class (for example PuzzleCharacter or PuzlePawn in PuzzlePlayerController) and store reference for later usage. Be aware that in this case you should implement Unpossess as well, so you can clear your stored reference and behave correctly in any given situation.
Say now I have a base class, let's call it GameEngine. The GameEngine class inherited several functions from another class. Now I have several game states and I need to apply sub-class polymorphism to this problem: several game states all need to draw background of the game window. The point is, I must have only ONE class to initialise my game window. My problem is, when I need to change my game states from one to another, how can I do it? Essentially, how can I use different version of subclass function(say DrawBackground) from my superclass?
The code:
BaseEngine *gameEngine;
gameEngine = new MenuState(this);
iResult = gameEngine->Initialise(...); // To initialise the window
// I need to find a way to transfer my state from Menu to Play after the window is initialised
iResult = gameEngine->MainLoop(); // To refresh the window (in case of background changed)
gameEngine->Deinitialise();
So in the above code, I have a BaseEngine which can do several functions (draw something to the window). And I now have two game states, MenuState and PlayState. There is one virtual function in my BaseEngine called DrawBackground() and I need to redefine it(different behaviour) in my Menu and Play states. Now the point is only one state(whether Base, Menu or Play) can initialise the window. However I need it to use different version of my derived class (Menu and Play) to draw different background when state is changed.
It is not really clear what you are asking but it feels like what you want is strategy pattern (that is, in simple words, changing some internal object/algorithm that does the job).
When dealing with inheritance, you should follow the so-called is-a relationship (Wikipedia on Inheritance). In your question, GameEngine is not a state (specifically MenuState).
What you should actually do is to implement the states as a strategy for GameEngine (See Strategy Pattern on Wikipedia, some, including me, call it Policy Pattern which is more self explanatory I think). You could have several classes inheriting from, say BaseState, and you should set these states on GameEngine via something like GameEngine::setState(std::unique_ptr<BaseState> state). The GameEngine will act differently according to the strategy set on it. So in a simple case, we can say that GameEngine::MainLoop() will call the virtual BaseState::draw() function. So the data that gets drawn is simply controlled by the policy set on the GameEngine using GameEngine::setState().
To put it simply, move the behavior to the BaseState strategy and change the strategy to change the behavior.
Optionally you could use some event mechanism to change the strategy (state). There is Boost.Signal, Qt has its own and there are others but it is straightforward to implement one for simple needs, easier thanks to C++11.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I know how to code and use simple classes, and I even know how inheritance works and how to use it. However, there's a very limited amount of guides on how to actually design the structure of your class hierarchy, or even how to design a simple class? Also, when and why should I inherit (or use) a class?
So I'm not really asking about how, I'm asking when and why. Example codes are always a good way to learn, so I would appreciate them. Also, emphasize the progress of designing rather than simply giving one sentence on when and why.
I program mainly in C++, C# and Python, but I'll probably understand the simple examples in most languages.
If any of the terms seem mixed up or so, feel free to edit my question. I'm not a native and I'm not sure of all the words.
I'll use C++ as an example language, since it relies so much on inheritance and classes.
Here's a simple guide on how to build controls for a simple OS, such as windows.
Controls include simple objects on your windows, such as buttons, sliders, textboxes, etc.
Building a basic class.
This part of the guide applies for (almost) any class.
Remember, well planned is half done.
What kind of class are we working on?
Which are it's attributes and what methods does it need?
These are the main questions we need to think of.
We're working on OS controls here, so let's begin with a simple class, shall it be Button. Now, what are the attributes on our button? Obviously it needs a position on the window. Also, we don't want every button to be exact same size, so size is an other attribute. Button also "needs" a label (the text drawn on the button). This is what you do with each class, you design it and then code it. Now I know which attributes I need, so lets build the class.
class Button
{
private:
Point m_position;
Size m_size;
std::string m_label;
}
Notice how I've left out all the getters and setter and other methods for the sake of shorter code, but you'd have to include those too. I'm also expecting us to have Point and Size classes, normally we'd have to struct them ourselves.
Moving onto the next class.
Now that we got one class (Button) finished, we can move to the next class.
Let's go with Slider, the bar which e.g. helps you scroll web pages up and down.
Let's begin like we did on button, what does our slider class need?
It's got location (position) on the window and size of the slider. Also, it's got minimum and maximum values (minimum means that the scroller is set to the top of the slider, and maximum means it's on the bottom). We also need the current value, i.e. where the scroller is at the moment. This is enough for now, we can build our class:
class Slider
{
private:
Point m_position;
Size m_size;
int m_minValue;
int m_maxValue;
int m_currentValue;
}
Creating a base class.
Now that we got two classes, the first thing we notice is we just defined Point m_position; and Size m_size; attributes on both classes. This means we have two classes with common elements and we just wrote the same code twice, wouldn't it be awesome if we could write the code only once and tell both of our classes to use that code instead of rewriting? Well, we can.
Creating a base class is "always" (there are exceptions, but beginners shouldn't worry about them) recommended if we have two similar classes with common attributes, in this case Button and Slider. They are both controls on our OS with size and position. From this we get a new class, called Control:
class Control
{
private:
Point m_position;
Size m_size;
}
Inheriting similar classes from common base class.
Now that we got our Control class, which includes the common items for every control, we can tell our Button and Slider to inherit from it. This will save us time, computer's memory and eventually time. Here's our new classes:
class Control
{
private:
Point m_position;
Size m_size;
}
class Button : public Control
{
private:
std::string m_label
}
class Slider : public Control
{
private:
int m_minValue;
int m_maxValue;
int m_currentValue;
}
Now some people might say that writing Point m_position; Size m_size; twice is much easier than writing twice : public Control and creating the Control class.
This might be true in some cases, but it's still recommended not to write the same code twice, especially not when creating classes.
Besides, who knows how many common attributes we'll eventually find. Later on we might realize we need Control* m_parent member to the Control class, which points to the window (or panel or such) in which our control is held in.
An other thing is, if we later on realize that on top of Slider and Button we also need TextBox, we can just create a textbox control by saying class TextBox : public Control { ... } and only write the textbox specific member variables, instead of size, position and parent again and again on every class.
Final thoughts.
Basically always when you have two classes with common attributes or methods, you should create a base class.
This is the basic rule, but you are allowed to use your own brain since there might be some exceptions.
I am not a professional coder myself either, but I'm learning and I've taught you everything as my educators have taught it to me. I hope you (or atleast someone) will find this answer useful.
And even though some people say that python and other duck typing languages don't even need to use inheritance, they're wrong.
Using inheritance will save you so much time and money on larger projects, and eventually you'll thank yourself for creating the base classes.
The reusability and management of your project will become billion times easier.
You need to use inheritance, when you have a situation where there are two classes, that contains the attributes of a single class, or when there are two classes, in which one is dependant on the other. Eg)
class animal:
#something
class dog(animal):
#something
class cat(animal):
#something
Here, there are two classes , dog and cat, that have the attributes of the class animal. Here , inheritance plays its role.
class parent:
#something
class child(parent):
#something
Here, parent and child are two classes, where the child is dependant of the parent, where the child has the attributes of the parent and its own unique ones. So, inheritance is used here.
It depends on the language.
In Python for example you normally don't need a lot of inheritance because you can pass any object to any function and if the objects implements the proper methods everything will be fine.
class Dog:
def __init__(self, name):
self.name = name
def sing(self):
return self.name + " barks"
class Cat:
def __init__(self, name):
self.name = name
def sing(self):
return self.name + " meows"
In the above code Dog and Cat are unrelated classes, but you can pass an instance of either to a function that uses name and calls method sing.
In C++ instead you would be forced to add a base class (e.g. Animal) and to declare those two classes as derived.
Of course inheritance is implemented and useful in Python too, but in many cases in which it's necessary in say C++ or Java you can just avoid it thanks to "duck typing".
However if you want for example to inherit implementation of some methods (in this case the constructor) then inheritance could be use with Python too with
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def sing(self):
return self.name + " barks"
class Cat(Animal):
def sing(self):
return self.name + " meows"
The dark side of inheritance is that your classes will be more coupled and more difficult to reuse in other contexts you cannot foresee now.
Someone said that with object oriented programming (actually class oriented programming) sometimes you just need a banana and instead you get a gorilla holding a banana and a whole jungle with it.
I'd start with definition of class from wikipedia:
In object-oriented programming, a class is a construct that is used to
create instances of itself – referred to as class instances, class
objects, instance objects or simply objects. A class defines
constituent members which enable its instances to have state and
behavior. Data field members (member variables or instance variables)
enable a class instance to maintain state. Other kinds of members,
especially methods, enable the behavior of class instances. Classes
define the type of their instances
Often you see examples that uses dogs, animals, cats and so on. But let's get to something practical.
First and most straight forward case when you need a class is when you need (or rather you should) to encapsulate certain functions and methods together, because they simply make sense together. Let's imagine something simple: HTTP request.
What do you need when creating HTTP request? Server, port, protocol, headers, URI... You could put all that into dict like {'server': 'google.com'} but when you use class for this, you'll just make it explicit that you need these attributes together and you'll be using them to do this one particular task.
For the methods. You could again create method fetch(dict_of_settings), but whole functionality is bound to attributes of HTTP class and just doesn't make sense without them.
class HTTP:
def __init__(self):
self.server = ...
self.port = ...
...
def fetch(self):
connect to self.server on port self.port
...
r1 = HTTP(...)
r2 = HTTP(...)
r1.port = ...
data = r1.fetch()
Isn't it nice and readable?
Abstract classes/Interfaces
This point, just quick... Assume you want to implement dependency injection in your project for this particular case: you want your application to be independent on database engine.
So you propose interface (represented by abstract class) which should each database connector implement and then rely on generic methods in your application. Lets say that you define DatabaseConnectorAbstract (you don't have to actually define in python, but you do in C++/C# when proposing interface) with methods:
class DatabaseConnectorAbstract:
def connect(): raise NotImplementedError( )
def fetch_articles_list(): raise NotImplementedError( )
...
# And build mysql implementation
class DatabaseConnectorMysql(DatabaseConnectorAbstract):
...
# And finally use it in your application
class Application:
def __init__(self,database_connector):
if not isinstanceof(database_connector, DatabaseConnectorAbstract):
raise TypeError()
# And now you can rely that database_connector either implements all
# required methods or raises not implemented exception
Class hierarchy
Python exceptions. Just take a look for a second on the hierarchy there.
ArithmeticError is generic Exception and in some cases it can get as particular as saying FloatingPointError. This is extremely useful when handling exceptions.
You can realize this better on .NET forms when object has to be instance of Control when adding to form, but can be practically anything else. The whole point is that object is DataGridView while still being Control (and implementing all methods and properties). This is closely connected with abstract classes and interfaces and one of many real-life examples could be HTML elements:
class HtmlElement: pass # Provides basic escaping
class HtmlInput(HtmlElement): pass # Adds handling for values and types
class HtmlSelect(HtmlInput): pass # Select is input with multiple options
class HtmlContainer(HtmlElement): pass # div,p... can contain unlimited number of HtmlElements
class HtmlForm(HtmlContainer): pass # Handles action, method, onsubmit
I've tried to make it as brief as possible, so feel free to ask in comment.
Since you are primarily interested in the big picture, and not the mechanics of class design, you might want to familiarize yourself with the S.O.L.I.D. principles of object-oriented design. It's not a strict procedure, but a set or rules to support your own judgement and taste.
The essence is that a class represents a single responsiblity (the S). It does one thing and does it well. It should represent an abstraction, preferably one representing a piece of your application's logic (encapsulating both behavior and data to support that behavior). It could also be an aggregation abstraction of multiple related data field. The class is the unit of such encapsulation and is responsible for maintaining the invariants of your abstractions.
The way to build classes is to be both open to extensions and closed to modifications (the O). Identify likely changes in your class's dependencies (either types or constants that you used in its interface and implementation). You want the interface to be complete enough so that it can extended, yet you want its implementation to be robust enough so that it won't have to be changed for that.
That's two principles about the class as the basic building block. Now on to building hierarchies, which represents class relationships.
Hierarchies are built through inheritance or composition. The key principle here is that you only use inheritance to model strict Liskov-substitutability (the L). This is a fancy way of saying that you only use inheritance for is-a relationships. For anything else (barring some technical exceptions to get some minor implementation advantages) you use composition. This will keep your system as loosely coupled as possible.
At some point many different clients might depend on your classes for different reasons. This will grow your class hierarchy and some of the classes lower in the hierarchy can get overly large ("fat") interfaces. When that happens (and in practice it's a matter of taste and judgement) you seggregate your general-purpose class interface into many client-specific interfaces (the I).
As your hierarchy grows even further, it might appear to form a pyramid when you draw it with the basic classes on top and their subclasses or composities below it. This will mean that your higher-level application layers will depend on lower-level details. You can avoid such brittleness (which for example manifests itself through large compile times or very big cascades of changes following minor refactorings) by letting both the higher-level layer and the lower-level layer depend on abstractions (i.e. interfaces, which in C++ e.g. can be implemented as abstract classes or template parameters). Such dependency inversion (the D) once again helps to loosen couplings between the various parts of your application.
That's it: five solid pieces of advice that are more or less language independent and have stood the test of time. Software design is hard, these rules are to keep you out of the most frequently occuring types of trouble, everything else comes through practice.
I had faced the problem. In my C++ hierarchy tree I have two branches for entities of difference nature, but same behavior - same interface. I created such hierarchy trees (first in image below).
And now I want to work with Item or Base classes independetly of their nature (first or second). Then I create one abstract branch for this use. My mind build (second in image below).
But it not working. Working scheme seems (third in image below).
It's bad logic, I think...
Do anybody have some ideas about such hierarchy inheritance? How make it more logical? More simple for understanding?
Image
Sorry for my english - russian internet didn't help:)
Update:
You ask me to be more explicit, and I will be.
In my project (plugins for Adobe Framemaker) I need to work with dialogs and GUI controls. In some places I working with WinAPI controls, and some other places with FDK (internal Framemaker) controls, but I want to work throw same interface.
I can't use one base class and inherite others from it, because all needed controls - is a hierarchy tree (not one class).
So I have one hierarchy tree for WinAPI controls, one for FDK and one abstract tree to use anyone control.
For example, there is an Edit control (WinEdit and FdkEdit realization), a Button control (WinButton and FdkButton realization) and base entity - Control (WinControl and FdkControl realization).
For now I can link my classes in realization trees (Win and Fdk) with inheritence between each of them (WinControl is base class for WinButton and WinEdit; FdkControl is base class for FdkButton and FdkEdit). And I can link to abstract classes (Control is base class for WinControl and FdkControl; Edit is base class for WinEdit and FdkEdit; Button is base class for WinButton and FdkButton). But I can't link my abstract tree - compiler swears.
In fact I have two hierarchy trees, that I want to inherite from another one.
Update:
I have done this quest! :)
I used the virtual inheritence and get such scheme (http://img12.imageshack.us/img12/7782/99614779.png). Abstract tree has only absolute abstract methods. All inheritence in abstract tree are virtual. Link from realization tree to abstract are virtual. On image shown only one realization tree for simplicity.
Thanks for help!
C++ supports multiple inheritance, so you can have the union of (2) and (3), making sure that AbstractBase is always declared as a virtual base class.
Without knowing the real meaning and purpose of the various classes, it's difficult to offer any better advice.
It's not clear from the description if this would work for you but typically classes with a common interface would define the interface in AbstractBase and then have concrete instances inherit directly from that (FirstItem, SecondItem).
Why the extra indirection(s) in your examples? What's expected to be in AbstractItem, FirstBase and SecondBase?
For using different implementations of one interface, on could use:
the Bridge Design Pattern
You might couple this with a Factory Design Pattern so as to construct your two implementations differently.
However, it may look too simple for your classes architecture.
But as the comments under your answer say: it is difficult to imagine the job/role of your classes with such names. You should be more explicit, so as we can think of a precise design.