From 53aa88a5008a5ab8fe7e64056a620a7f1d76ecdb Mon Sep 17 00:00:00 2001 From: Lasse Christiansen Date: Fri, 13 Apr 2012 11:31:00 +0200 Subject: [PATCH] Added makefile. Added DiLite src. --- makefile | 18 +++++ src/dilite/di.h | 161 +++++++++++++++++++++++++++++++++++++++++ src/dilite/singleton.h | 73 +++++++++++++++++++ src/factory.cpp | 11 +++ src/factory.h | 27 +++++++ src/i_warrior.h | 74 +++++++++++++++++++ src/i_weapon.h | 45 ++++++++++++ src/main.cpp | 26 +++++++ src/samurai.cpp | 57 +++++++++++++++ src/samurai.h | 69 ++++++++++++++++++ src/shuriken.cpp | 30 ++++++++ src/shuriken.h | 53 ++++++++++++++ src/sword.cpp | 21 ++++++ src/sword.h | 47 ++++++++++++ 14 files changed, 712 insertions(+) create mode 100644 makefile create mode 100644 src/dilite/di.h create mode 100644 src/dilite/singleton.h create mode 100644 src/factory.cpp create mode 100644 src/factory.h create mode 100644 src/i_warrior.h create mode 100644 src/i_weapon.h create mode 100644 src/main.cpp create mode 100644 src/samurai.cpp create mode 100644 src/samurai.h create mode 100644 src/shuriken.cpp create mode 100644 src/shuriken.h create mode 100644 src/sword.cpp create mode 100644 src/sword.h diff --git a/makefile b/makefile new file mode 100644 index 0000000..5ead726 --- /dev/null +++ b/makefile @@ -0,0 +1,18 @@ +CC=g++ +CFLAGS= -c -Wall -ansi -pedantic +LDFLAGS= +SOURCES= src/main.cpp src/sword.cpp src/shuriken.cpp src/samurai.cpp src/factory.cpp +OBJECTS=$(SOURCES:.cpp=.o) +EXECUTABLE=samurai +LIBS= -lboost_thread + +all: $(SOURCES) $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o bin/$@ + +.cpp.o: + $(CC) $(CFLAGS) $< -o $@ + +clean: + rm -f src/*.o bin/$(EXECUTABLE) \ No newline at end of file diff --git a/src/dilite/di.h b/src/dilite/di.h new file mode 100644 index 0000000..addd879 --- /dev/null +++ b/src/dilite/di.h @@ -0,0 +1,161 @@ +#ifndef BASEIOC_H +#define BASEIOC_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "singleton.h" + +namespace DiLite +{ + /** + Template used to create instance of specific type T. + + @return Void pointer to object instance. + */ + template void* CreateInstance() { return new T; } + + /** + The Dependency Injection (DI) container class. + + @author SW801 + */ + class BaseDI + { + private: + /** A map of to create object instances */ + std::map _objectConstructors; + + /** A map of to refer to singleton instances */ + std::map _singletons; + + /** + Checks if an object constructor or singleton of type I has been registered. + */ + template void CheckExistence() + { + if(_singletons.find(typeid(I).name()) != _singletons.end() || _objectConstructors.find(typeid(I).name()) != _objectConstructors.end()) + throw std::runtime_error(((std::string) typeid(I).name()) + " is already bound."); + } + + /** + Type parameter constraint: checks that T is derived from B + Courtesy of: Bjarne Stroustrup, + http://www2.research.att.com/~bs/bs_faq2.html#constraints + */ + template struct Derived_from + { + static void constraints(T* p) + { + B* pb = p; + } + Derived_from() + { + void(*p)(T*) = constraints; + } + }; + + public: + /** + Bind type I in transient scope using construction function. + Each time resolved, a new instance is created and returned. + + @param pt2func Function pointer to construction function. + */ + template void Bind(I*(*pt2func)()) + { + CheckExistence(); + _objectConstructors[typeid(I).name()] = (void*(*)())pt2func; + } + + /** + Bind type I to type T in transient scope using default constructor of T. + Each time resolved, a new instance is created and returned. + */ + template void Bind() + { + Derived_from(); + CheckExistence(); + _objectConstructors[typeid(I).name()] = &CreateInstance; + } + + /** + Bind type I to type T in singleton scope using default constructor of T. + Each time resolved, the same instance is returned. + */ + template void BindSingle() + { + Derived_from(); + CheckExistence(); + _singletons[typeid(I).name()] = &Singleton::GetInstance(); + } + + /** + Bind type I to type T in singleton scope using construction function. + Each time resolved, the same instance is returned. + + @param pt2func Function pointer to construction function. + */ + template void BindSingle(I*(*pt2func)()) + { + Derived_from(); + CheckExistence(); + _singletons[typeid(I).name()] = &Singleton::CreateInstance((void*(*)())pt2func); + } + + /** + Resolve an instance of the desired type/interface. + + Object may be pre-existing if registered as singleton. + Otherwise lazily constructed using an object constructor. + */ + template I* Resolve() + { + // Check if "resolvable" from singleton scope + if(_singletons.find(typeid(I).name()) != _singletons.end()) + return ((I*)_singletons[typeid(I).name()]); + + // Check if "resolvable" from transient scope + if(_objectConstructors.find(typeid(I).name()) != _objectConstructors.end()) + return ((I*)_objectConstructors[typeid(I).name()]()); + + // Binding not found + throw std::runtime_error(((std::string) typeid(I).name()) + " is not bound."); + } + + /** + Unbinds every registered object constructor and singleton instance. + */ + template void Unbind() + { + // Unbind all objects in transient scope + std::map::iterator it_transients = _objectConstructors.find(typeid(I).name()); + + if (it_transients != _objectConstructors.end()) + { + _objectConstructors.erase(it_transients); + } + + // Unbind all objects in singleton scope + std::map::iterator it_singletons = _singletons.find(typeid(I).name()); + + if (it_singletons != _singletons.end()) + { + _singletons.erase(it_singletons); + } + } + }; + + /** + Typedefinition of the Singleton DI container. + */ + typedef Singleton DI; +} + +#endif diff --git a/src/dilite/singleton.h b/src/dilite/singleton.h new file mode 100644 index 0000000..96e5ccb --- /dev/null +++ b/src/dilite/singleton.h @@ -0,0 +1,73 @@ +#ifndef SINGLETON_H_SW8 +#define SINGLETON_H_SW8 + +#include +#include + +namespace DiLite +{ + /** + Template for any class that should be in + singleton scope. + */ + template class Singleton + { + private: + /** Indicates if the singleton has been destructed */ + static bool _isDestructed; + + /** The mutex used by the singleton to enable thread-safety */ + static boost::mutex& GetMutex() + { + static boost::mutex mutex; + return mutex; + } + + /** Prevent construction of Singleton class */ + Singleton() {} + + /** Prevent destruction of Singleton class */ + ~Singleton() { _isDestructed = true; } + + /** Prevent copy of Singleton */ + Singleton(Singleton const&); + + /** Prevent assignment to Singleton */ + void operator=(Singleton const&); + + public: + /** + Gets the instance wrapped by the Singleton. + + @return A singleton object of type T. + */ + static T& GetInstance() + { + assert(!_isDestructed); + boost::mutex::scoped_lock lock(GetMutex()); + static T instance; + return instance; + } + + /** + Creates and gets an instance of type T in singleton scope. + + @param ctor A function pointer to a construction function returning T. + @return A singleton object of type T. + */ + static T& CreateInstance(void*(*ctor)()) + { + assert(!_isDestructed); + boost::mutex::scoped_lock lock(GetMutex()); + static T instance = *((T*)ctor()); + return instance; + } + }; + + /** + Force creation of the mutex before main() is called. + This happens as a consequence of the comma-operator and semantics of sequence points. + */ + template bool Singleton::_isDestructed = (Singleton::GetMutex(), false); +} +#endif diff --git a/src/factory.cpp b/src/factory.cpp new file mode 100644 index 0000000..b977bff --- /dev/null +++ b/src/factory.cpp @@ -0,0 +1,11 @@ +#include "factory.h" +#include "i_weapon.h" +#include "samurai.h" + +namespace SampleCode +{ + IWarrior* Factory::CreateSamurai() + { + return new Samurai(DiLite::DI::GetInstance().Resolve()); + } +} diff --git a/src/factory.h b/src/factory.h new file mode 100644 index 0000000..410bab9 --- /dev/null +++ b/src/factory.h @@ -0,0 +1,27 @@ +#ifndef FACTORY_H +#define FACTORY_H + +#include "dilite/di.h" +#include "i_warrior.h" + +namespace SampleCode +{ + /** + A factory class to instantiate objects in the program. + Provides coupling between the running program and the + DI framework. + + @author SW801 + */ + class Factory + { + public: + /** + Creates a new Samurai using the DI framework. + + @return IWarrior pointer to the Samurai object. + */ + static IWarrior* CreateSamurai(); + }; +} +#endif diff --git a/src/i_warrior.h b/src/i_warrior.h new file mode 100644 index 0000000..d04fa76 --- /dev/null +++ b/src/i_warrior.h @@ -0,0 +1,74 @@ +#ifndef I_WARRIOR +#define I_WARRIOR + +#include + +namespace SampleCode +{ + /** + Interface for warriors. + */ + class IWarrior + { + + protected: + /** The name of the warrior */ + std::string _name; + + /** The remaining life of the warrior */ + int _life; + + public: + /** + Constructor + + @param name The name of the warrior. + @param life The initial life of the warrior. + */ + IWarrior(const std::string& name, int life): _name(name), _life(life) {} + + /** + Attacks an opponent. + + @param opponent The opponent to attack. + */ + virtual void Attack(IWarrior* opponent) const = 0; + + /** + Takes damage from an opponents hit. + + @param damage The damage to receive. + */ + virtual void TakeDamage(int damage) = 0; + + /** + Accessor function for the name. + + @post Does not change the object. + @return Name of the warrior. + */ + virtual std::string GetName() const = 0; + + /** + Mutator function for the name. + + @param newName The new name for the warrior. + */ + virtual void SetName(const std::string& newName) = 0; + + /** + Accessor function for the alive property of the warrior. + + @post Does not change the object. + @return True if alive. + */ + virtual bool IsAlive() const = 0; + + /** + Empty deconstructor. + */ + virtual ~IWarrior() {} + }; +} + +#endif diff --git a/src/i_weapon.h b/src/i_weapon.h new file mode 100644 index 0000000..9fa9db5 --- /dev/null +++ b/src/i_weapon.h @@ -0,0 +1,45 @@ +#ifndef I_WEAPON_H +#define I_WEAPON_H + +#include + +namespace SampleCode +{ + /** + Interface for weapons. + */ + class IWeapon + { + public: + /** + Use the weapon. + + @post Does not change the object. + @return The damage given by the weapon. + */ + virtual int Use() = 0; + + /** + Accessor function for the name. + + @post Does not change the object. + @return The name of the weapon. + */ + virtual std::string GetName() const = 0; + + /** + Accessor function for the broken property. + + @post Does not change the object. + @return True if broken. + */ + virtual bool IsBroken() const = 0; + + /** + Empty deconstructor. + */ + virtual ~IWeapon() {} + }; +} + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..081d28e --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,26 @@ +#include "dilite/di.h" +#include "i_warrior.h" +#include "i_weapon.h" +#include "shuriken.h" +#include "factory.h" + +int main(int argc, char const *argv[]) +{ + using namespace DiLite; + using namespace SampleCode; + + DI::GetInstance().Bind(); + DI::GetInstance().Bind(&Factory::CreateSamurai); + + IWarrior* w1 = DI::GetInstance().Resolve(); + IWarrior* w2 = DI::GetInstance().Resolve(); + + w1->SetName("Doi Toshikatsu"); + w2->SetName("Imagawa Yoshimoto"); + w1->Attack(w2); + + delete w1; + delete w2; + + return 0; +} diff --git a/src/samurai.cpp b/src/samurai.cpp new file mode 100644 index 0000000..4ef8827 --- /dev/null +++ b/src/samurai.cpp @@ -0,0 +1,57 @@ +#include +#include "samurai.h" + +namespace SampleCode +{ + Samurai::Samurai(IWeapon* w) : IWarrior("Unnamed Samurai", 100), _weapon(w) {} + + void Samurai::Attack(IWarrior* opponent) const + { + int damage = _weapon->Use(); + std::cout << _name << " hits " << opponent->GetName() << " with a \"" << _weapon->GetName() << "\", dealing " << damage << " points of damage!" << std::endl; + opponent->TakeDamage(damage); + } + + void Samurai::TakeDamage(int damage) + { + if (_life > 0) + { + if (damage == 0) + { + std::cout << _name << " laughs at the pointless attack!" << std::endl; + } + else + { + _life -= damage; + if (_life <= 0) + { + std::cout << _name << " dies" << std::endl; + } + } + } + else + { + std::cout << "Leave " << _name << " alone!" << std::endl; + } + } + + std::string Samurai::GetName() const + { + return _name; + } + + void Samurai::SetName(const std::string& newName) + { + _name = newName; + } + + bool Samurai::IsAlive() const + { + return !(_life <= 0); + } + + Samurai::~Samurai() + { + delete _weapon; + } +} diff --git a/src/samurai.h b/src/samurai.h new file mode 100644 index 0000000..8df917a --- /dev/null +++ b/src/samurai.h @@ -0,0 +1,69 @@ +#ifndef SAMURAI_H +#define SAMURAI_H + +#include +#include "i_weapon.h" +#include "i_warrior.h" + +namespace SampleCode +{ + /** + A Samurai warrior + */ + class Samurai : public IWarrior + { + private: + /** The weapon of the warrior */ + IWeapon* _weapon; + + public: + /** + Constructor. + + @param w The weapon to use + */ + Samurai(IWeapon* w); + + /** + Attack an oppononent. + + @param opponent The opponent to attack. + @post Does not change the object. + */ + void Attack(IWarrior* opponent) const; + + /** + Take damage from the warrior when hit by opponent + + @param damage The damage to receive. + */ + void TakeDamage(int damage); + + /** + Accessor function for the name. + + @post Does not change the object. + @return The name of the warrior. + */ + std::string GetName() const; + + /** + Mutator function for the name. + + @param newName The new name for the warrior. + */ + void SetName(const std::string& newName); + + /** + Accessor function for the alive property. + */ + bool IsAlive() const; + + /** + Destructor + */ + ~Samurai(); + }; +} + +#endif diff --git a/src/shuriken.cpp b/src/shuriken.cpp new file mode 100644 index 0000000..f06500f --- /dev/null +++ b/src/shuriken.cpp @@ -0,0 +1,30 @@ +#include +#include "shuriken.h" + +namespace SampleCode +{ + Shuriken::Shuriken() : _damage(20), _quantity(100) {} + + int Shuriken::Use() + { + if(!IsBroken()) + { + _quantity -= 10; + return _damage; + } + else + { + return 0; + } + } + + std::string Shuriken::GetName() const + { + return "Shuriken of Might"; + } + + bool Shuriken::IsBroken() const + { + return _quantity <= 0; + } +} diff --git a/src/shuriken.h b/src/shuriken.h new file mode 100644 index 0000000..fb463d0 --- /dev/null +++ b/src/shuriken.h @@ -0,0 +1,53 @@ +#ifndef SHURIKEN_H +#define SHURIKEN_H + +#include +#include "i_weapon.h" + +namespace SampleCode +{ + /** + A Shuriken (ancient Japanese) weapon + that can be used by warriors + */ + class Shuriken : public IWeapon + { + private: + /** The damage given by the weapon */ + int _damage; + + /** The remaining quantity of shurikens */ + int _quantity; + + public: + /** + Default constructor + + @post The damage and quantity are initialized to zero. + */ + Shuriken(); + + /** + Use the weapon. + + @return Damage given by weapon + */ + int Use(); + + /** + Accessor function for the name. + + @return The weapons name. + */ + std::string GetName() const; + + /** + Accessor function for the broken property. + + @return True if the weapon is broken. + */ + bool IsBroken() const; + }; +} + +#endif diff --git a/src/sword.cpp b/src/sword.cpp new file mode 100644 index 0000000..fbdb690 --- /dev/null +++ b/src/sword.cpp @@ -0,0 +1,21 @@ +#include "sword.h" + +namespace SampleCode +{ + Sword::Sword() : _damage(5) {} + + int Sword::Use() + { + return _damage; + } + + std::string Sword::GetName() const + { + return "Deadly sharp sword"; + } + + bool Sword::IsBroken() const + { + return false; + } +} diff --git a/src/sword.h b/src/sword.h new file mode 100644 index 0000000..e51878d --- /dev/null +++ b/src/sword.h @@ -0,0 +1,47 @@ +#ifndef SWORD_H +#define SWORD_H + +#include +#include "i_weapon.h" + +namespace SampleCode +{ + /** + A classic sword for use by warriors. + */ + class Sword : public IWeapon + { + private: + /** The damage given by the weapon on hit */ + int _damage; + + public: + /** Default constructor */ + Sword(); + + /** + Use the weapon + + @return The amount of damage given by the weapon. + */ + int Use(); + + /** + Accessor function for the name + + @post Does not change the object. + @return The name of the weapon. + */ + std::string GetName() const; + + /** + Accessor function for the broken property + + @post Does not change the object. + @return True if weapon is broken. + */ + bool IsBroken() const; + }; +} + +#endif