Designing Classes: Each class encapsulate object of other related class - oop

I am stuck with the design problem. I could not come up with any good solution. Here is the problem statement.
I have set of devices, each of these devices has some common properties and behavior. Each device may contain 1 or more than one other type of devices connected to it. For example : If there are 4 set of devices A,B,C,D and A being the root of all the devices.
A will have one or many B devices.
B will have one or many C devices.
C will have one or many D devices.
All these different set of devices have some common properties while some are exclusive to themselves.
I have to create a report which will read the data from these objects and read it to file. Report is in XML format and will depict hierarchy of whole system.
How could I approach this problem ? Any suggestion comment would be of great help.

This sounds like a case for the Visitor pattern. You let the Visitor visit each of the children of A. For each child, it'll again visit all children, and so on.
While the Visitor traverses the tree, you collect data about each node. You can, in this case, for example collect the data directly in XML if you want.
The Visitor pattern works well with heterogeneous data types, but it's OK when some of the nodes have common structure as well.

Visitor pattern is a better way of performing operations that where all parent and child classes should be accepted as input and in which behavior is dictated by the object type.
Here's C++ Implementation for your reference:
#include <vector>
#include <iostream>
using namespace std;
class Visitor
{
public:
virtual void visit(class Node *, class Common*) = 0;
virtual void visit(class CompositeNode *, Common*) = 0;
};
class Common
{
int value;
public:
Common(int val)
{
value = val;
}
virtual void traverse()
{
cout << value << " | ";
}
virtual void accept(Visitor &, Common*) = 0;
};
class Node: public Common
{
public:
Node(int val): Common(val){}
virtual void accept(Visitor &v, Common *c)
{
v.visit(this, c);
}
};
class CompositeNode: public Common
{
vector < Common * > children;
public:
CompositeNode(int val): Common(val){}
void add(Common *ele)
{
children.push_back(ele);
}
virtual void accept(Visitor &v, Common *c)
{
v.visit(this, c);
}
virtual void traverse()
{
Common::traverse();
for (int i = 0; i < children.size(); i++)
children[i]->traverse();
}
};
class AddVisitor: public Visitor
{
public:
virtual void visit(Node *, Common*)
{
}
virtual void visit(CompositeNode *node, Common *c)
{
node->add(c);
}
};
int main()
{
Common *nodes[3];
nodes[0] = new CompositeNode(0); //Consider A
nodes[1] = new CompositeNode(1); //Consider B
nodes[2] = new CompositeNode(2); //Consider B
AddVisitor addVisitor;
nodes[0]->accept(addVisitor, nodes[1]); //B
nodes[0]->accept(addVisitor, nodes[2]); //B
nodes[1]->accept(addVisitor, new Node(3)); //Consider C
nodes[1]->accept(addVisitor, new Node(4)); //Consider C
nodes[2]->accept(addVisitor, new Node(5)); //Consider C
nodes[2]->accept(addVisitor, new Node(6)); //Consider C
for (int i = 0; i < 3; i++)
{
cout<<"--------------------------------"<<endl;
nodes[i]->traverse();
cout<<endl;
}
}
Output
--------------------------------
0 | 1 | 3 | 4 | 2 | 5 | 6 |
--------------------------------
1 | 3 | 4 |
--------------------------------
2 | 5 | 6 |

Related

How to show collaboration diagram in Doxygen only for objects/classes related to a specific group tag

I have created a markdown file as part of a c++ project intended to describe a specific functionality in the project.
In this markdown file, I have defined a group using '\defgroup myGroup Explanation of group'
I've also tagged all objects related to this group by including the \ingroup tag for the group in question.
The question is on how to render UML diagrams only for the context for this specific group in the detailed section of the module for this functionality?
I have read through the doxygen documentation and have not found any information on how to define the group context boundaries for rendering a specific group of objects/classes using graphviz.
#include <string>
#include <iostream>
/**
* #ingroup markingsgroup
* #brief This class defines a base class
*/
class BaseClass
{
public:
BaseClass() {}
virtual bool getStatus(void) const = 0;
virtual void setStatus(const bool status) = 0;
};
/**
* #ingroup markingsgroup
* This class defines Class1
*/
class Class1 : public BaseClass
{
public:
Class1() {}
bool getStatus() const
{
return m_status;
}
void setStatus(const bool status)
{
m_status = status;
}
private:
bool m_status;
};
/**
* #ingroup markingsgroup
* This class defines a Class2
*/
class Class2 : public BaseClass
{
public:
Class2() {}
bool getStatus() const
{
return m_status;
}
void setStatus(const bool status)
{
m_status = status;
}
private:
bool m_status;
};
/**
* #ingroup markingsgroup
* #brief Main function
*/
int main(int argc, char *argv[])
{
Class1 myClass1;
Class2 myClass2;
myClass1.setStatus(true);
myClass2.setStatus(myClass1.getStatus());
std::cout << "Class1: " << myClass1.getStatus() << " Class2: " << myClass2.getStatus() << std::endl;
}
Doxyfile changes form default:
PROJECT_NAME = "My Project"
PROJECT_NAME = "Marking Project"
OUTPUT_DIRECTORY = /home/fblidner/doxgentest/documentation
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_PACKAGE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_METHODS = YES
INPUT = project
RECURSIVE = YES
GENERATE_XML = YES
XML_PROGRAMLISTING = NO
UML_LOOK = YES
CALLER_GRAPH = YES
PLANTUML_JAR_PATH = /home/fblidner/puppet-manifests/devvm/files/generated/plantuml.jar
MAX_DOT_GRAPH_DEPTH = 10
HAVE_DOT = YES
CALLER_GRAPH = YES

OptaPlaner simple example cant find feasible solution

to get familiar with optaplanner i created a simple test project. I only have one Solution and one Entity class. The Entity has only one value between 0 and 9. There should only be odd numbers and the sum of all should be less then 10 (this are just some random constraints i came up with).
As Score i use a simple HardSoftScore. Here is the code:
public class TestScoreCalculator implements EasyScoreCalculator<TestSolution>{
#Override
public HardSoftScore calculateScore(TestSolution sol) {
int hardScore = 0;
int softScore = 0;
int valueSum = 0;
for (TestEntity entity : sol.getTestEntities()) {
valueSum += entity.getValue() == null? 0 : entity.getValue();
}
// hard Score
for (TestEntity entity : sol.getTestEntities()) {
if(entity.getValue() == null || entity.getValue() % 2 == 0)
hardScore -= 1; // constraint: only odd numbers
}
if(valueSum > 10)
hardScore -= 2; // constraint: sum should be less than 11
// soft Score
softScore = valueSum; // maximize
return HardSoftScore.valueOf(hardScore, softScore);
}
}
and this is my config file:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
<!-- Domain model configuration -->
<scanAnnotatedClasses/>
<!-- Score configuration -->
<scoreDirectorFactory>
<easyScoreCalculatorClass>score.TestScoreCalculator</easyScoreCalculatorClass>
</scoreDirectorFactory>
<!-- Optimization algorithms configuration -->
<termination>
<secondsSpentLimit>30</secondsSpentLimit>
</termination>
</solver>
for some reason OptaPlanner cant find a feasible solution. It terminates with LS step (161217), time spent (29910), score (-2hard/10soft), best score (-2hard/10soft)... and the solution 9 1 0 0.
So the hardScore is -2 because the two 0 are not odd. A possible solution would be 7 1 1 1 for example. Why is this ? This should be a really easy example ...
(when i set the Start values to 7 1 1 1 it terminates with this solution and a score of (0hard/10soft) how it should be)
Edit:
The Entity class
#PlanningEntity
public class TestEntity {
private Integer value;
#PlanningVariable(valueRangeProviderRefs = {"TestEntityValueRange"})
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
#ValueRangeProvider(id = "TestEntityValueRange")
public CountableValueRange<Integer> getStartPeriodRange() {
return ValueRangeFactory.createIntValueRange(0, 10);
}
}
The Solution class
#PlanningSolution
public class TestSolution {
private List<TestEntity> TestEntities;
private HardSoftScore score;
#PlanningEntityCollectionProperty
public List<TestEntity> getTestEntities() {
return TestEntities;
}
public void setTestEntities(List<TestEntity> testEntities) {
TestEntities = testEntities;
}
#PlanningScore
public HardSoftScore getScore() {
return score;
}
public void setScore(HardSoftScore score) {
this.score = score;
}
#Override
public String toString() {
String str = "";
for (TestEntity testEntity : TestEntities)
str += testEntity.getValue()+" ";
return str;
}
}
The Main Program class
public class Main {
public static final String SOLVER_CONFIG = "score/TestConfig.xml";
public static int printCount = 0;
public static void main(String[] args) {
init();
}
private static void init() {
SolverFactory<TestSolution> solverFactory = SolverFactory.createFromXmlResource(SOLVER_CONFIG);
Solver<TestSolution> solver = solverFactory.buildSolver();
TestSolution model = new TestSolution();
List<TestEntity> list = new ArrayList<TestEntity>();
// list.add(new TestEntity(){{setValue(7);}});
// list.add(new TestEntity(){{setValue(1);}});
// list.add(new TestEntity(){{setValue(1);}});
// list.add(new TestEntity(){{setValue(1);}});
for (int i = 0; i < 4; i++) {
list.add(new TestEntity());
}
model.setTestEntities(list);
// Solve the problem
TestSolution solution = solver.solve(model);
// Display the result
System.out.println(solution);
}
}
It gets stuck in a local optima because there is no move that takes 1 from entity and gives it to another entity. With a custom move you can add that.
These kind of moves only apply to numeric value ranges (which are rare, usually value ranges are a list of employees etc), but they should probably exist out of the box (feel free to create a jira for them).
Anyway, another way to get the good solution is to add <exhaustiveSearch/>, that bypassing local search and therefore the local optima. But that doesn't scale well.

Why am I getting a NullPointerException in my project?

This is the beginning of my project:
//class variables
private static int numberOfCouples;
//object arrays
private static Witch[] witch;
private static Wizard[] wizard;
//ranking arrays
private static int[][] witchPartnerRanking;
private static int[][] wizardPartnerRanking;
//proposal array
private static boolean[][] proposal;
//DO NOT ALTER THE MAIN METHOD
public static void main(String[] args) throws FileNotFoundException {
go( "coven_dance.txt" );
System.out.println( "Witch array:" );
for ( int i = 0; i < witch.length; i++ ) {
System.out.printf( "Witch %d:, name: %-20s, current partner id: %2d, proposals made: %d%n",
witch[ i ].getId(), witch[ i ].getName(), witch[ i ].getParnerWizardId(), witch[ i ].getNumberOfProposals() );
A NullPointerException happens on the last line. Even though I have this:
private static void go( String fileName ) throws FileNotFoundException {
//1. READ THE FILE
Scanner inStream = new Scanner( new File ( fileName ));
numberOfCouples = inStream.nextInt();
// System.out.println(howManyCouples);
//System.out.print(
inStream.nextLine();
//2. CREATE AND POPULATE THE witch ARRAY
/*Witch[]*/ witch = new Witch[numberOfCouples*2];
/*int [][]*/ witchPartnerRanking = new int[numberOfCouples*2][numberOfCouples];
for (int i = 0; i < numberOfCouples*2; i++) {
if(inStream.hasNextInt()){
//4. CREATE AND POPULATE THE witchPartnerRanking ARRAY
int j = 0;
while(inStream.hasNextInt() && j<numberOfCouples){
int prefer = inStream.nextInt();
//System.out.println(prefer);
witchPartnerRanking[i][j] = prefer;
j++;
}
String bob = inStream.nextLine();
//System.out.println(bob);
}
else{
String name = inStream.next();
//System.out.println(name);
Witch the = new Witch(i, name);
witch[i] = the;
}
}
I'm not sure what's going on. If anyone could help, that would be awesome.
Here's the file I'm reading from if you need it:
4
NannyOgg 0 2 3 1
TiffanyAching 3 2 0 1
MagratGarlick 0 3 2 1
GrannyWeatherwax 0 3 2 1
TheLibrarian 2 1 3 0
PonderStibbons 2 1 3 0
LordVetinari 1 2 0 3
DEATH 3 2 1 0
You witch array is being accessed without being initialized.
You have private static Witch[] witch; which is declared but not initialized
You need to initialize it. One way to do so is:
private static Witch[] witch = new Witch[10]; // replace 10 with any array size you want
In Java, arrays are treated as regular objects. Whenever you are accessing an object that is null, you get a NullPointerException.

serialize/deserialize user defined class variable?

Suppose I have two classes:
class1 {
int m_i;
std::string m_s;
};
class2 {
int m_i2;
class1 *m_ptr;
};
Now, I want to send a class2 variable over network, and want to use any of the libraries that does serialization.(Protocol-buffers, Thrift, MessagePack..)
Which one can I use?(note the class1* m_ptr)
You could use thrift for this.
the definition would look something like
struct class1 {
1: required i32 m_i;
2: required string m_s;
}
struct class2 {
1: required i32 m_i2;
2: optional class1 m_ptr;
}
You would like to read this excellent guide
http://diwakergupta.github.com/thrift-missing-guide/
and to get clarity on concern about the "pointer" issue that you mentioned in the question,read the section on "How are nested structs initialized?" in the above guide.
Using google protocol buffers, you would need a .proto file (say test.proto) like:
package serialisation; // puts this in namespace serialisation
message class1 {
required int32 m_i = 1;
required bytes m_s = 2;
}
message class2 {
required int32 m_i2 = 1;
optional class1 m_ptr = 2;
}
Using C++, once you run the protoc compiler against this, you end up with test.pb.cc and test.pb.h
You can then use these like:
#include <string>
#include "test.pb.h"
struct class1 {
int m_i;
std::string m_s;
};
struct class2 {
int m_i2;
class1 *m_ptr;
};
int main() {
class2 second_class;
second_class.m_i2 = 2;
second_class.m_ptr = new class1;
second_class.m_ptr->m_i = 1;
second_class.m_ptr->m_s = "one";
// Serialise class 2
serialisation::class2 serialisable_second_class;
serialisable_second_class.set_m_i2(second_class.m_i2);
if (second_class.m_ptr) {
serialisation::class1* serialisable_first_class = serialisable_second_class.mutable_m_ptr();
serialisable_first_class->set_m_i(second_class.m_ptr->m_i);
serialisable_first_class->set_m_s(second_class.m_ptr->m_s);
}
std::string serialised(serialisable_second_class.SerializeAsString());
// Parse class 2
serialisation::class2 parsed_second_class;
parsed_second_class.ParseFromString(serialised);
class2 retrieved_second_class;
retrieved_second_class.m_i2 = parsed_second_class.m_i2();
if (parsed_second_class.has_m_ptr()) {
retrieved_second_class.m_ptr = new class1;
retrieved_second_class.m_ptr->m_i = parsed_second_class.m_ptr().m_i();
retrieved_second_class.m_ptr->m_s = parsed_second_class.m_ptr().m_s();
} else {
retrieved_second_class.m_ptr = nullptr;
}
return 0;
}
Note, for the sake of brevity I'm not doing any error checking or exception handling here - this would be needed in production code. I'm also not managing the lifetime of the class1 pointer.

Best way of structuring methods to handle derived types

I have an inheritance hierarchy similar to below and I want to write my DAL to persist these objects but am unsure as to the best way of structuring it?
Pet <- Dog <- Alsation and Labrador
Pet <- Cat <- Persian and Tabby
Although all classes inherit from Pet, each method will need to call a different stored procedure and add different sql parameters. There will be some common parameters though.
A few ideas:
(1) PetDal with overloaded save method that takes in each derived type.
(2) PetDal with separate SaveLabrador, SaveTabby methods.
(3) Base PetDal plus inherited LabradorDal, TabbyDal classes, one per dervied type with a common interface. eg void Save(Pet pet) which would need to cast the pet to the derived type within each method (strategy method).
(4) Some other way.
(1) and (2) are really the same, just syntactically different. One problem with (4) is that if you want to deal with different persistent types (flat files, databases etc) then you will have to have a class for each permutation (AlsationToFileDAL, AlsationToSybaseDAL, etc).
You could use (1)/(2) with double dispatch, e.g.:
// pets.h
#include <string>
#include <iostream>
class Alsation;
class Persian;
class PetDAL
{
public:
virtual ~PetDAL () {}
virtual void save (const Alsation* alsation) = 0;
virtual void save (const Persian* persian) = 0;
};
class Pet
{
std::string name_;
public:
Pet (const std::string& name) : name_ (name)
{}
virtual ~Pet () {}
std::string getName () const
{
return name_;
}
virtual void save (PetDAL* dal) const = 0;
};
class Dog : public Pet
{
bool sleepWalks_;
public:
Dog (const std::string& name, bool sleepWalks) : Pet (name), sleepWalks_ (sleepWalks)
{}
bool getSleepWalks () const {return sleepWalks_;}
};
class Alsation : public Dog
{
public:
Alsation (const std::string& name, bool sleepWalks) : Dog (name, sleepWalks)
{}
virtual void save (PetDAL* dal) const
{
dal->save (this);
}
};
class Cat : public Pet
{
int purrsPerMinute_;
public:
Cat (const std::string& name, int purrsPerMinute) : Pet (name), purrsPerMinute_ (purrsPerMinute)
{}
int getPurrsPerMinute () const {return purrsPerMinute_;}
};
class Persian : public Cat
{
public:
Persian (const std::string& name, int purrsPerMinute) : Cat (name, purrsPerMinute)
{}
virtual void save (PetDAL* dal) const
{
dal->save (this);
}
};
class PetDALCoutImpl : public PetDAL
{
public:
virtual void save (const Alsation* alsation)
{
std::cout << "Saving alsation " << std::endl
<< "\tname=" << alsation->getName () << std::endl
<< "\tsleepwalks=" << alsation->getSleepWalks () << std::endl;
}
virtual void save (const Persian* persian)
{
std::cout << "Saving persian " << std::endl
<< "\tname=" << persian->getName () << std::endl
<< "\tpurrsPerMinute=" << persian->getPurrsPerMinute () << std::endl;
}
};
int test (int argc, char* argv[])
{
Dog* dog = new Alsation ("fido", true);
Cat* cat = new Persian ("dave", 10);
PetDAL* petDAL = new PetDALCoutImpl ();
dog->save (petDAL);
cat->save (petDAL);
delete cat;
delete dog;
return 0;
};
I.e. the Pet base class knows its subclasses can be saved to a DAL, but it has no dependency on the DAL implementations.
Have you thought about using a pattern like the strategy pattern? It might fit your needs as you can have different strategies for different implementations, whilst still using properties/methods from the abstract class?