I want to make the program with the following classes:
Class Player, which stores some information about players with get/set functions.
Player can be as AttackPlayer, which will have own data with get/set functions.
Also Player can be as ProtectorPlayer, also with some other own data with get/set functions different than in AttackPlayer.
Also Player can be TeamPlayer or FreePlayer, each of these classes have own data etc.
The question is how to implement the hierarchy correctly?
At first I thought about multiple inheritance, which is not good anyway.
Something like:
Player
AttackPlayer extends Player
ProtectorPlayer extends Player
TeamPlayer extend AttackPlayer or ProtectorPlayer
FreePlayer extend AttackPlayer or ProtectorPlayer
Also I thought something about strategy pattern, but it is not applicable here, because there are no common algorithms.
Are there any approaches which helps to organize such interaction?
Another way to do it is to have a field in the Player class, which helps to identify wether the TeamPlayer/FreePlayer is Attack or Protector type, and access appropriate fields depending on that.
In this case inheritance would be like this:
Player
TeamPlayer extends Player
FreePlayer extends Player
Attack, Protect structs or classes without inheritance, but as fields in Player class.
But I don't like such an approach and I am searching for a better design.
IMHO inheritance is the wrong model for this. Instead I would have a player class and different roles for it. It depends if a player can have multiple roles at the same time. I would use a strategy pattern.
How about composition and interface/dependency injection ?
<?php
interface IPlayer {
public function __toString();
}
class Player implements IPlayer {
protected $_id;
protected $_name;
public function __construct( $id, $name ) {
$this->_id = $id;
$this->_name = $name;
}
public function getId() { return $this->_id; }
public function setId($id) { $this->_id = $id; }
public function setName($n) { $this->_name = $n; }
public function getName() { return $this->_name; }
public function __toString() {
return 'my name is ' . $this->_name . ' and my id is ' . $this->_id;
}
}
class ComposedPlayer implements IPlayer {
protected $_player;
public function __construct( IPlayer $p ) {
$this->_player = $p;
}
public function __set($k, $v) {
$this->_player->$k = $v;
}
public function __get($k) {
return $this->_player->$k;
}
public function __call($func, $args) {
return call_user_func_array( array( $this->_player, $func ), $args );
}
public function __toString() {
return $this->_player->__toString();
}
}
class AttackPlayer extends ComposedPlayer {
function getNameMod() {
return 'attack player ' . $this->getName();
}
public function __toString() {
return parent::__toString() . ' and im an attack player';
}
}
class ProtectedPlayer extends ComposedPlayer {
function getNameMod() {
return 'protected player ' . $this->getName();
}
public function __toString() {
return parent::__toString() . ' and im an protected player';
}
}
class TeamPlayer extends ComposedPlayer {
function getIdMod() {
return $this->getId() - 10;
}
public function __toString() {
return parent::__toString() . ' and im an team player';
}
}
class FreePlayer extends ComposedPlayer {
function getIdMod() {
return $this->getId() + 10;
}
public function __toString() {
return parent::__toString() . ' and im an free player';
}
}
$free_attack_player = new FreePlayer( new AttackPlayer( new Player( 100, 'John' ) ) );
$free_protected_player = new FreePlayer( new ProtectedPlayer( new Player( 101, 'Bob' ) ) );
$team_attack_player = new TeamPlayer( new AttackPlayer( new Player( 102, 'Bill' ) ) );
$team_protected_player = new TeamPlayer( new ProtectedPlayer( new Player( 104, 'Jim' ) ) );
foreach ( array( $free_attack_player, $free_protected_player, $team_attack_player, $team_protected_player ) as $p ) {
echo 'id: ', $p->getId(), ' name: ', $p->getName(), ' mod id: ', $p->getIdMod(), ' mod name: ', $p->getNameMod(), PHP_EOL;
}
foreach ( array( $free_attack_player, $free_protected_player, $team_attack_player, $team_protected_player ) as $p ) {
echo $p, PHP_EOL;
}
Executing this will yield:
id: 100 name: John mod id: 110 mod name: attack player John
id: 101 name: Bob mod id: 111 mod name: protected player Bob
id: 102 name: Bill mod id: 92 mod name: attack player Bill
id: 104 name: Jim mod id: 94 mod name: protected player Jim
my name is John and my id is 100 and im an attack player and im an free player
my name is Bob and my id is 101 and im an protected player and im an free player
my name is Bill and my id is 102 and im an attack player and im an team player
my name is Jim and my id is 104 and im an protected player and im an team player
EDIT: updated to add a __toString() to the interface, an easy example of method composition.
This may be a problem where TDD can come very handy. The approach seems slow at first, but it is very useful when the design in not obvious. TDD tends to cause the design to emerge from the code itself.
If you are interested in giving TDD a try, you can maybe start from this blog, written by our company coach. Also, if you can, take a look at the two episodes here related to TDD (episode 6a and 6b): they are from Uncle Bob, so really suggested lectures/watch.
Player can be TeamPlayer or FreePlayer
TeamPlayer extend AttackPlayer or ProtectorPlayer FreePlayer extend AttackPlayer or ProtectorPlayer
I think, that this approach is ok. Think about the storing data. If you want to store it in the db, it would be nice approach: you have Player table with all of the player data, and create other tables(that extend Player table) to store data for different types of players.
Look at the Class Table Inheritance
In fact, inheritance hierarchy can be greater than one, but not more than 4. If inheritance is obvious, that is ok. The main rule is keeping complexity low.
On the other hand, if you are not going to store this data in db or foreign keys in player object to Free object etc. seems more obvious in your case - use another approach.
It can be mix of factory and Strategy as below:
Player can be Team Player or Free Player and can play using Attacker or Protector strategy. So Free Player or Team Player can inherit Player class and in them we can associate Playing strategy which can be Attacker or Protector. So in this case program initiator can call Factory to decide whether player is Free Player or Team Player and can pass the Strategy to use to play. Having strategy as association in Player will help keep code more extensible to add new strategies. Factory for type of player is separate from strategy so can extend independently. Using too much inheritance can cause issues in performance and maintenance of code.
Please do not take words like "extend" as java specific.
Related
Imagine you have some Entity class and want another class that groups multiple instances of Entity.
How do you name it?
CompoundEntity?
CompositeEntity?
something else?
This is a common thing I do, and my colleagues use different naming convention. I have no idea what is better and also I'm not a native English speaker.
Concrete example:
public final class CompoundSetUpAction: SetUpAction {
private let setUpActions: [SetUpAction]
public init(
setUpActions: [SetUpAction])
{
self.setUpActions = setUpActions
}
public func setUp() -> TearDownAction {
return CompoundTearDownAction(
tearDownActions: Array(setUpActions.map { $0.setUp() }.reversed())
)
}
}
I've been asked some kind of interesting questions related to OOP.
Here's the question.
Alice has started a restaurant and created software the determine the price of all the items on the menu
She started by creating a class for each menu item so that the price can be calculated using an interface.
interface HasPrice {
getPrice(): number;
}
class Ramen implements HasPrice {
getPrice() {
return 5;
}
}
class Spaghetti implements HasPrice {
getPrice() {
return 10;
}
}
She then decided there should be topping so she used the decorator pattern.
class RamenWithPork extends Ramen {
getPrice() {
super.getPrice() + 3;
}
}
This worked until she decided to expand the topping menu and it became too cumbersome to deal combinatorial amount of classes. How should she fix it?
follow up question: With all the choices, customers have started asking whether or not their choice of ingredients contains certain allergens.
Alice would prefer not to have to add a million methods to all her classes to specify true/false for each allergen. How can she add this check without having to add one function per allergen for each ingredient?
Sometimes when you create a class you can add there several properties (new data members) that you are not certain if you want to do or not. For example, I have a casino slots game. I have tiles and tiles are spinning on different reels. So once 3 tiles come on the same line then player wins 3$, 4 tiles - 4$ and 5 tiles - 5$ for tile A and for tile B player wins 5$, 10$, 20$ accordingly. Should, for example, each tile store the data of its reward or there should be a reward manager for checking how many tiles are consecutive next to each other to give the reward to the player?
Please note that I don't want to have such a situation. But I find me many times thinking "Should I add this data, and consequently, corresponding logic the my class or not?". I worry about single responsibility principle when I want to have different managers for such things, but on the other hand I came to a situation to create several singletons or singleton-like classes.
Well, this sounds a lot like a use case for the Strategy Pattern.
As far as I am concerned (never been to a casino, since they're prohibited here in my country), most of slot machines work the same way.
So, you might think of one implementation as (pseudo-java code):
class Figure {
private String representation;
}
class Slot {
private Set<Figure> figures;
public Figure getRandom() {
// retrieve random figure from a slot
}
}
interface IRewardStrategy {
public int getReward(SlotMachine machine);
}
class OneFoldRewardStrategy implements IRewardStrategy {
public int getReward(SlotMachine machine) {
return machine.getCurrentLinedSlotsCount();
}
}
class TenFoldRewardStrategy implements IRewardStrategy {
public int getReward(SlotMachine machine) {
return 10 * machine.getCurrentLinedSlotsCount();
}
}
class SlotMachine {
private int slotCount;
private List<Slot> slots;
private List<Figure> currentRollResult;
private IRewardStrategy rs;
public SlotMachine(List<Slot> slots, IRewardStrategy rs) {
this.slots = slots;
this.rs = rs;
}
public void roll() {
// For each slot, get random figure
}
public int getTotalSlots() {
return slotCount;
}
public int getCurrentLinedSlotsCount() {
// Iterates over the current roll result and get the number of lined slots
}
public int getReward() {
this.rs.getReward(this); // delegates to the reward strategy
}
}
// Usage
SlotMachine machine = new SlotMachine(..., new TenFoldRewardStrategy());
machine.roll(); // suppose this give 3 slots in a row...
print(machine.getReward()); // This will yield 30
Attention: This is a very bare code, just to give you an idea, it has several problems.
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'm building an app with Laravel 4 and using Eloquent as the ORM.
I think the easiest way to describe my question is with an example, albeit an unlikely one...
I have a Cookie model (as in OREO etc). Cookie can in turn belong to a Human or an Alien. So...
Is it possible (correct) to say:
A Cookie belongs to Human
AND
A Cookie belongs to Alien?
The same Cookie can't belong to both a Human and and Alien or shared between members of the same species.
So I guess what I'm really asking is, can the Cookie table have two foreign key columns, one for Humans and one for Aliens?
Thanks in advance for your advice.
You can have this:
name type nullable
------------------------------
id int no
name text no
human_id int yes
alien_id int yes
Those could be your classes:
class Cookie extends Eloquent {
public function human()
{
return $this->belongsTo('Human', 'human_id');
}
public function alien()
{
return $this->belongsTo('Alien', 'alien_id');
}
}
class Alien extends Eloquent {
public function cookie()
{
return $this->hasOne('Cookie', 'alien_id');
}
}
class Human extends Eloquent {
public function cookie()
{
return $this->hasOne('Cookie', 'human_id');
}
}
And then you could use them this way:
$human = Human::find(1);
echo $human->cookie->name;
$cookie = Cookie::find(1);
if ($cookie->human) echo $cookie->human->name;
if ($cookie->alien) echo $cookie->alien->name;