Tags » Design Pattern

Rewriting the Event Manager

Since the beginning I was aware that one of the most critical and difficult part of the development of Wizards’ Duel would have been the… 729 more words

Development

Learning Design Pattern From Unit Test Framework 4 (Template Method Pattern)

承接上一篇文章的Example 5,我們將在以下的範例將Test class用Macro來表示,畢竟每寫一個Test就要時做一個class也太麻煩了,而且每個test class都大同小異,用一個Macro來表示,可以讓User方便的撰寫Tests。

===== Example 6 =====

#include <iostream>
#include <vector>
#include <string>
#include <assert.h>

//----- production code -----
int Add(int a, int b) {
    return a + b;
}

int Subtract(int a, int b) {
    return a - b;
}

//----- testing code -----
#define ASSERT_EQUAL(m, n) \
    if(m != n) \
    {\
        result.failed++;\
        std::cout << "Failed at line: " << __LINE__ << std::endl;\
        std::cout << "Actual: " << m << std::endl;\
        std::cout << "Expected: " << n << std::endl;\
    }\
    else\
    {\
        result.succeeded++;\
    }

#define TEST_CASE_NAME(testCaseName) testCaseName##_TEST

#define MY_TEST(testCaseName)\
class TEST_CASE_NAME(testCaseName) : public CTestCase \
{\
public: \
    TEST_CASE_NAME(testCaseName)(std::string name) : CTestCase(name) {}\
    virtual void Run(TestResult& result);\
private: \
    static bool bTricky;\
};\
bool TEST_CASE_NAME(testCaseName)::bTricky = CUnitTest::GetInstance().Register(new TEST_CASE_NAME(testCaseName)(#testCaseName));\
void TEST_CASE_NAME(testCaseName)::Run(TestResult& result) \

struct TestResult {
    int succeeded;
    int failed;
};

class CTestCase {
public:
    CTestCase(std::string strName) : m_strName(strName) { }

    const std::string GetTestName() const { return m_strName; }

    virtual void Run(TestResult& result) = 0;

private:
    std::string m_strName;
};

class CUnitTest
{
private:
    CUnitTest() { }
    ~CUnitTest()
    {
        if (m_testCases.size() != 0) {
            for (size_t i = 0; i < m_testCases.size(); ++i) {
                delete m_testCases[i];
            }
        }

        m_testCases.clear();
    }

public:
    static CUnitTest& GetInstance() {
        static CUnitTest instance;
        return instance;
    }

    bool Register(CTestCase* pCmd) {
        m_testCases.push_back(pCmd);
        return true;
    }

    void Run() {
        TestResult result = { 0, 0 };

        for (auto it = m_testCases.begin(); it != m_testCases.end(); ++it) {
            std::cout << "Execute " << (*it)->GetTestName() << " ..." << std::endl;
            (*it)->Run(result);
        }

        std::cout << std::endl << "----- Summary -----" << std::endl;
        std::cout << "Total " << result.succeeded + result.failed << " test(s)" << std::endl;
        std::cout << result.succeeded << " test(s) scucceed" << std::endl;
        std::cout << result.failed << " test(s) failed" << std::endl;
    }

private:
    std::vector<CTestCase*> m_testCases;
};

MY_TEST(TestAdd) {
    ASSERT_EQUAL(Add(1, 2), 3);
    ASSERT_EQUAL(Add(2, 2), 8);
}

MY_TEST(TestSubtract) {
    ASSERT_EQUAL(Subtract(1, 2), -1);
    ASSERT_EQUAL(Subtract(1, 1), -1);
    ASSERT_EQUAL(Subtract(3, 2), 1);
}

void main() {
    CUnitTest::GetInstance().Run();

    std::cout << "test ok..." << std::endl;
}
… 490 more words

Learning Design Pattern From Unit Test Framework 3 (Singleton Pattern)

再來我們要解決的是第一篇文章一開始提到的第1個問題:簡化Test的撰寫,讓User在撰寫Tests時可以自動把Tests register到CUnitTest這個class裡面。我們會透過一個很tricky的static private member vairable來達成這個任務。

===== Example 5 =====

#include <iostream>
#include <vector>
#include <string>
#include <assert.h>

//----- production code -----
int Add(int a, int b) {
    return a + b;
}

int Subtract(int a, int b) {
    return a - b;
}

//----- testing code -----
#define ASSERT_EQUAL(m, n) \
    if(m != n) \
    {\
        result.failed++;\
        std::cout << "Failed at line: " << __LINE__ << std::endl;\
        std::cout << "Actual: " << m << std::endl;\
        std::cout << "Expected: " << n << std::endl;\
    }\
    else\
    {\
        result.succeeded++;\
    }

struct TestResult {
    int succeeded;
    int failed;
};

class CTestCase {
public:
    CTestCase(std::string strName) : m_strName(strName) { }

    const std::string GetTestName() const { return m_strName; }

    virtual void Run(TestResult& result) = 0;

private:
    std::string m_strName;
};

class CUnitTest
{
private:
    CUnitTest() { }
    ~CUnitTest()
    {
        if (m_testCases.size() != 0) {
            for (size_t i = 0; i < m_testCases.size(); ++i) {
                delete m_testCases[i];
            }
        }

        m_testCases.clear();
    }

public:
    static CUnitTest& GetInstance()
    {
        static CUnitTest instance;
        return instance;
    }

    bool Register(CTestCase* pCmd) {
        m_testCases.push_back(pCmd);
        return true;
    }

    void Run() {
        TestResult result = { 0, 0 };

        for (auto it = m_testCases.begin(); it != m_testCases.end(); ++it) {
            std::cout << "Execute " << (*it)->GetTestName() << " ..." << std::endl;
            (*it)->Run(result);
        }

        std::cout << std::endl << "----- Summary -----" << std::endl;
        std::cout << "Total " << result.succeeded + result.failed << " test(s)" << std::endl;
        std::cout << result.succeeded << " test(s) scucceed" << std::endl;
        std::cout << result.failed << " test(s) failed" << std::endl;
    }

private:
    std::vector<CTestCase*> m_testCases;
};

class CTestAdd : public CTestCase {
public:
    CTestAdd(std::string strName) : CTestCase(strName) { }

    virtual void Run(TestResult& result) {
        ASSERT_EQUAL(Add(1, 2), 3);
        ASSERT_EQUAL(Add(2, 2), 8);
    }

private:
    static bool bTricky;
};
bool CTestAdd::bTricky = CUnitTest::GetInstance().Register(new CTestAdd("Add"));

class CTestSubtract : public CTestCase {
public:
    CTestSubtract(std::string strName) : CTestCase(strName) { }

    virtual void Run(TestResult& result) {
        ASSERT_EQUAL(Subtract(1, 2), -1);
        ASSERT_EQUAL(Subtract(1, 1), -1);
        ASSERT_EQUAL(Subtract(3, 2), 1);
    }

private:
    static bool bTricky;
};
bool CTestSubtract::bTricky = CUnitTest::GetInstance().Register(new CTestSubtract("Subtract"));

void main() {
    CUnitTest::GetInstance().Run();

    std::cout << "test ok..." << std::endl;
}
… 33 more words

Learning Design Pattern From Unit Test Framework 2 (Collecting Parameter Pattern)

接下來我們把在上一篇文章中Example 2的code稍微整理一下。

===== Example 3 =====

#include <iostream>
#include <vector>
#include <string>
#include <assert.h>

//----- production code -----
int Add(int a, int b)
{
    return a + b;
}

int Subtract(int a, int b)
{
    return a - b;
}

//----- testing code -----
class CTestCase
{
public:
    CTestCase(std::string strName) :
        m_strName(strName)
    {
    } 

    const std::string GetTestName() const { return m_strName; }

    virtual void Run() = 0;

private:
    std::string m_strName;
};

class CTestAdd : public CTestCase
{
public:
    CTestAdd(std::string strName) : CTestCase(strName)
    {
    }

    virtual void Run()
    {
        assert(Add(1, 2) == 3);
    }
};

class CTestSubtract : public CTestCase
{
public:
    CTestSubtract(std::string strName) : CTestCase(strName)
    {
    }

    virtual void Run()
    {
        assert(Subtract(1, 2) == -1);
    }
};

class CUnitTest
{
public:
    CUnitTest() {}
    ~CUnitTest()
    {
        if (m_testCases.size() != 0)
        {
            for (size_t i = 0; i < m_testCases.size(); ++i)
            {
                delete m_testCases[i];
            }
        }

        m_testCases.clear();
    }

    void Register(CTestCase* pCmd)
    {
        m_testCases.push_back(pCmd);
    }

    void Run()
    {
        std::vector<CTestCase*>::iterator it = m_testCases.begin();
        for (; it != m_testCases.end(); ++it)
        {
            std::cout << "Execute " << (*it)->GetTestName() << " ..." << std::endl;
            (*it)->Run();
        }
    }

private:
    std::vector<CTestCase*> m_testCases;
};

void main()
{
    CUnitTest test;
    test.Register(new CTestAdd("Test Add"));
    test.Register(new CTestSubtract("Test Subtract"));
    test.Run();

    std::cout << "test ok..." << std::endl;
}
… 424 more words

Learning Design Pattern From Unit Test Framework 1 (Command Pattern)

本篇文章將深入探討Unit Test Framework的一些特性與實作。我們先從不用任何Unit Test Framework的例子開始,然後你將會發現這樣的寫法有其不便之處,而Unit Test Framework的使用,正是為了解決這些問題。

===== Example 1: Without framework =====

#include <iostream>
#include <assert.h>

int Add(int a, int b)
{
    return a + b;
}

int Subtract(int a, int b)
{
    return a - b;
}

void TestAdd()
{
    assert(Add(1, 2) == 3);
}

void TestSubstract()
{
    assert(Subtract(5, 3) == 2);
}

void main()
{
    TestAdd();
    TestSubstract();

    std::cout << "test ok..." << std::endl;
}
… 280 more words

Java 设计模式

1. Decorator
在一个object上加上一些额外的功能,即进行功能扩展。“allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class”. 45 more words

Java

Solid Principles

Single Responsibility Principle

It states:

  • Every class should have a single responsibility.
  • There should never be more than one reason for a class to change.
  • 356 more words
Design Pattern