Design patterns and UML

Design mode

Objectives:
The analysis and design of object-oriented system actually pursues two points: high cohesion and low coupling.
Core idea:
Isolation change

Classification:
Creative mode (new decoupling): hide the way of creating logic while creating objects, instead of directly instantiating objects with the new operator. (5 modes)

Structural pattern (class decoupling): focus on the combination of classes and objects. The concept of inheritance is used to combine interfaces and define how composite objects get new functions. Solve the coupling problem between patterns from the structure of the program. (7 modes)

Behavioral pattern (method decoupling): used to describe how classes or objects interact and how responsibilities are assigned. ("actions can also be abstracted into objects") (11 modes)

principle:
Open and closed principle: class changes are made through

class AbsBank
{
public: 
	virtual void Processing business() = 0;
};

class bank1:public AbsBank
{
public:
	virtual void Processing business()
	{
		//withdraw money
		
		//deposit
	}
};

class bank2:public AbsBank
{
	virtual void Processing business()
	{
		//Subscription fund
		
		//Other business
	}
		
};

class bank3:public AbsBank
{
	virtual void Processing business()
	{
		//New business: Loans
	}
};

int main()
{
	AbsBank * ab = new bank1;	
}

2. Dependency Inversion Principle: it depends on abstraction and not on concrete (don't write the class "dead")
3. Interface isolation principle: the dependencies between classes should be based on the smallest interface
Advantages and disadvantages of minimum interface?
Advantages: interface design is limited: the smaller the granularity of interface design, the more flexible the system is.
Disadvantages: the more complex the structure will be, the more difficult the development will be, and the maintainability will be reduced.

//Interface isolation principle

class AbsComputer
{
public:
	virtual void Play games() = 0;
	virtual void to work in an office() = 0;
	virtual void entertainment() = 0;
};

class Mycomputer:public AbsComputer
{
public:
	virtual void Play games()
	{

	}

	virtual void to work in an office()
	{

	}

	virtual void entertainment()
	{

	}
};

//optimization
class AbsComputer1
{
public:
	virtual void Play games() = 0;
};

class AbsComputer2
{
public:
	virtual void to work in an office() = 0;
};

class AbsComputer3
{
public:
	virtual void entertainment() = 0;
};


class MyComputer2:public AbsComputer1,public AbsComputer2
{
public:
	virtual void Play games()
	{

	}

	virtual void to work in an office()
	{

	}
};

**4. Richter substitution principle: * * where any base class can appear, subclasses must appear.
Advantages and disadvantages of inheritance?
advantage:
1. Code sharing to improve code reusability.
2. Improve code scalability.
Improve the openness of products or projects.
shortcoming
Inheritance is intrusive. As long as you inherit, you have the properties and methods of the parent class.
The flexibility of the parent class and the child class is reduced.
Enhanced coupling. When changing the constants, variables or methods of the parent class, you must also consider the modification of the child class. There may be a large piece of code to refactor.
**5. Composition Reuse Principle: * * is to use some existing objects in a new object to make it a part of the new object. Try to use composition / aggregation first rather than inheritance.
**6. Dimitri's Law: * * a software entity should interact with other entities as little as possible

Simple factory mode
Isolation change
Advantages: it provides a constant interface and hides the process of creating objects
Disadvantages: the factory class violates the opening and closing principle

#include <iostream>
using namespace std;
#include <string>

class Cal
{
public:
	int m_num1;
	int m_num2;

	virtual int getResult() = 0;
};

class AddOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 + this->m_num2;
	}
};

class SubOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 - this->m_num2;
	}
};

class MulOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 * this->m_num2;
	}
};

class DivOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 / this->m_num2;
	}
};


class factoryOperator
{
public:
	static Cal * operatorfactory(string op)
	{
		Cal * cal = NULL;
		if (op == "+")
		{
			cal = new AddOperator();
		}
		else if (op == "-")
		{
			cal = new SubOperator();
		}
		else if (op == "*")
		{
			cal = new MulOperator();
		}
		else if (op == "/")
		{
			cal = new DivOperator();
		}

		return cal;
	}

};

//Simple factory mode
//Isolation change
//Advantages: it provides a constant interface and hides the process of creating objects
//Disadvantages: the factory class violates the opening and closing principle
int main()
{
	string op;
	cout << "Please enter operator:" << endl;
	cin >> op;

	int num1 = 0;
	cout << "Please enter operand 1:" << endl;
	cin >> num1;

	int num2 = 0;
	cout << "Please enter operand 2:" << endl;
	cin >> num2;

	//Simple factory mode
	//Isolation change
	//Advantages: it provides a constant interface and hides the process of creating objects
	//Disadvantages: the factory class violates the opening and closing principle
	Cal * cal = factoryOperator::operatorfactory(op);


	cal->m_num1 = num1;
	cal->m_num2 = num2;

	cout << cal->getResult() << endl;

	return 0;
}

Factory mode:
Advantages: it hides the creation process of objects and provides a unified and unchanged interface
Disadvantages: it exposes the creation process of the factory

#include <iostream>
using namespace std;
#include <string>


class Cal
{
public:
	int m_num1;
	int m_num2;

	virtual int getResult() = 0;
};


class AddOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 + this->m_num2;
	}
};

class SubOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 - this->m_num2;
	}
};

class MulOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 * this->m_num2;
	}
};

class DivOperator :public Cal
{
public:
	virtual int getResult()
	{
		return this->m_num1 / this->m_num2;
	}
};
//Factory mode
//Advantages: it hides the creation process of objects and provides a unified and unchanged interface
//Disadvantages: it exposes the creation process of the factory
class AbsFactor
{
public:
	virtual Cal * factorOPerator() = 0;
};


class AddFactory :public AbsFactor
{
public:
	virtual Cal * factorOPerator()
	{
		Cal * cal = NULL;

		cal = new AddOperator();

		return cal;
	}
};

class SubFactory :public AbsFactor
{
public:
	virtual Cal * factorOPerator()
	{
		Cal *  cal = NULL;

		cal = new SubOperator();

		return cal;
	}
};


class MulFactory :public AbsFactor
{
	virtual Cal * factorOPerator()
	{
		Cal * cal = NULL;

		cal = new MulOperator();

		return cal;
	}
};


class DivFactory :public AbsFactor
{
	virtual Cal * factorOPerator()
	{
		Cal * cal = NULL;

		cal = new DivOperator();


		return cal;
	}
};
class Factory
{
public:
	static AbsFactor * factorcreate(string op)
	{
		AbsFactor * absfaction = NULL;
		if (op == "+")
		{
			absfaction = new AddFactory();
		}
		else if (op == "-")
		{
			absfaction = new SubFactory();
		}
		else if (op == "*")
		{
			absfaction = new MulFactory();
		}
		else if (op == "/")
		{
			absfaction = new DivFactory();
		}

		return absfaction;
	}
};



//Simple factory + factory mode
int main()
{
	string op;
	cout << "Please enter operator:" << endl;
	cin >> op;

	int num1 = 0;
	cout << "Please enter operand 1:" << endl;
	cin >> num1;

	int num2 = 0;
	cout << "Please enter operand 2:" << endl;
	cin >> num2;


	AbsFactor * absfaction = Factory::factorcreate(op);
	Cal *cal = NULL;

	
	cal = absfaction->factorOPerator();

	cal->m_num1 = num1;
	cal->m_num2 = num2;


	cout << "The result is:" << endl;
	cout<<cal->getResult()<<endl;

	return 0;
}

Ioc mechanism
IOC mechanism connection

//IOC mechanism

template <class T>
class Ioccontain
{
public:
	//Dependency injection
	template <class X>
	void insertType(string key)
	{
		if (m.find(key) == m.end())
		{
			function<T *()> f = []() {return new X;};
			m[key] = f;
		}
	}

	//Form stored in map container
	//("+",[](){return new AddFactory;})
	//("-",[](){return new SubFactory;})
	//..

	


	//Dependency extraction
	T * getType(string key)
	{
		if (m.find(key) != m.end())
		{
			function<T *()> f = m[key];
			return f();
		}
		else
		{
			return NULL;
		}
		
	}
	
private:
	map<string, function<T *()>> m;
};
void test01()
{
	string op;
	cout << "Please enter operator:" << endl;
	cin >> op;

	int num1 = 0;
	cout << "Please enter operand 1:" << endl;
	cin >> num1;

	int num2 = 0;
	cout << "Please enter operand 2:" << endl;
	cin >> num2;


	//Factory mode + IOC mechanism
	//Dependency injection
	Ioccontain<AbsFactor> c;
	c.insertType<AddFactory>("+");
	c.insertType<SubFactory>("-");
	c.insertType<MulFactory>("*");
	c.insertType<DivFactory>("/");

	AbsFactor * factory = NULL;
	factory = c.getType(op);

	Cal * cal = NULL;
	cal = factory->factorOPerator();

	cal->m_num1 = num1;
	cal->m_num2 = num2;

	cout << cal->getResult() << endl;

}

void test02()
{
	string op;
	cout << "Please enter operator:" << endl;
	cin >> op;

	int num1 = 0;
	cout << "Please enter operand 1:" << endl;
	cin >> num1;

	int num2 = 0;
	cout << "Please enter operand 2:" << endl;
	cin >> num2;


	//Factory mode + IOC container
	//Dependency injection
	Ioccontain<Cal> c;

	c.insertType<AddOperator>("+");
	c.insertType<SubOperator>("-");
	c.insertType<MulOperator>("*");
	c.insertType<DivOperator>("/");

	Cal * cal = NULL;

	cal = c.getType(op);

	cal->m_num1 = num1;
	cal->m_num2 = num2;

	cout << cal->getResult() << endl;
}

Singleton mode

Singleton mode - lazy - thread safe

#include <iostream>
using namespace std;
#include <string>
#include <unistd.h>
#include <pthread.h>


//Thread safety: lazy threads are unsafe; Starving thread safety
//Space efficiency: hungry Han style space waste
class singleton
{
private:
	singleton()
	{
		cout << "singleton()" << endl;
	}
public:
	static singleton * getInstance()
	{
		if (m_sigle == NULL)
		{
			pthread_mutex_lock(&mutex);
			if (m_sigle == NULL)
			{
				m_sigle = new singleton();	//Lazy style
			}
			pthread_mutex_unlock(&mutex);
		}
		return m_sigle;
	}

	static singleton * m_sigle;
	static pthread_mutex_t mutex;
};
//Lazy style
singleton * singleton:*:m_sigle = NULL;
pthread_mutex_t singleton::mutex = PTHREAD_MUTEX_INITIALIZER;


void * thread_func(void * arg)
{
	singleton * t = singleton::getInstance();
	printf("%d\n", t);
	sleep(1);
}


int main()
{
	pthread_t tid[10];

	for (int i = 0; i < 10; ++i)
	{
		pthread_create(&tid[i], NULL, thread_func, NULL);
	}

	for (int i = 0; i < 10; ++i)
	{
		pthread_join(tid[i], NULL);
	}
	return 0;
}

Singleton mode - Hungry Chinese style

#include <iostream>
using namespace std;
#include <string>


//Thread safety: hungry thread safety, lazy thread unsafe;
//Space efficiency: hungry Han style space waste
class singleton
{
private:
	singleton()
	{
		cout << "singleton()" << endl;
	}
public:
	static singleton * getInstance()
	{
		if (m_sigle == NULL)
		{
			m_sigle = new singleton();	//Lazy style
		}
	}

	static singleton * m_sigle;
};

//Lazy style
singleton * singleton::m_sigle = NULL;

//Hungry Han style
singleton * singleton::m_sigle = new singleton();

Supplement:
Relationship between classes in object-oriented programming:
The relationships between classes mainly include
1. Inheritance, 2 Realization

3. Dependency

4. Association

5. Aggregation

6. Composition

Tags: Design Pattern

Posted by Divine Winds on Tue, 24 May 2022 04:38:34 +0300