模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
重复 = 易错 + 难改
我们既然用了继承,并且肯定这个继承有意义,就应该要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。
当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。
//AbstractClass 抽象类,其实也就是一抽象模板,定义并实现了一个模板方法
class AbstractClass {
public:
virtual void PrimitiveOperatrion1() = 0;
virtual void PrimitiveOperatrion2() = 0;
void TemplateMethod()
{
PrimitiveOperatrion1();
PrimitiveOperatrion2();
cout << endl;
}
};
//实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应
class ConcreteClassA :public AbstractClass {
public:
void PrimitiveOperatrion1()
{
cout << "具体类A方法1实现" << endl;
}
void PrimitiveOperatrion2()
{
cout << "具体类A方法2实现" << endl;
}
};
class ConcreteClassB :public AbstractClass {
public:
void PrimitiveOperatrion1()
{
cout << "具体类B方法1实现" << endl;
}
void PrimitiveOperatrion2()
{
cout << "具体类B方法2实现" << endl;
}
};
//main
AbstractClass* c1 = new ConcreteClassA();
c1->TemplateMethod();
AbstractClass* c2 = new ConcreteClassB();
c2->TemplateMethod();
delete c1;
c1 = NULL;
delete c2;
c2 = NULL;
模板方法模式是通过把不变行为搬移到父类,去除子类中的重复代码来体现它的优势,提供了一个很好的代码复用平台。
当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。
迪米特法则–最少知识原则
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
前提是在类的结构设计上,每一个类都应当尽量降低成员的访问权限,就是说,一个类包装好自己的private状态,不需要让别的类知道的字段或行为就不要公开。类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。
外观模式
为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
class SubSystemOne {
public:
void MethodOne()
{
cout << "子系统方法1" << endl;
}
};
class SubSystemTwo {
public:
void MethodOne()
{
cout << "子系统方法2" << endl;
}
};
//外观类
class Facade {
private:
SubSystemOne* one;
SubSystemTwo* two;
public:
Facade()
{
one = new SubSystemOne();
two = new SubSystemTwo();
}
void Method()
{
cout << "方法组" << endl;
one->MethodOne();
two->MethodOne();
}
};
//main
Facade* facade = new Facade();
facade->Method();
外观模式在什么时候使用最好呢?首先,在设计初期阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层和业务逻辑层、业务逻辑层和表示层的层与层之间建立外观Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。其次,在开发阶段,子系统往往因为不断地重构演化而变得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,但也给外部调用他们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为他们包含非常重要的功能,新的需求开发必须要依赖于它,此时用外观Facade也是非常合适的。可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与外观Facade对象交互,Facade与遗留代码交互所有复杂的工作。
建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要在定义一个具体的建造者就可以了。
//产品类
class Product {
list<string> parts;
public:
void Add(string part)
{
parts.push_back(part);
}
void Show()
{
for(string part : parts)
{
cout << part << endl;
}
}
};
//抽象建造者类
class Builder {
public:
virtual void BuildPartA() = 0;
virtual void BuildPartB() = 0;
virtual Product* GetResult() = 0;
};
//实例化建造者
class ConcreteBuilder1 :public Builder
{
private:
Product* product = new Product();
public:
void BuildPartA()
{
product->Add("邮件A");
}
void BuildPartB()
{
product->Add("邮件B");
}
Product* GetResult()
{
return product;
}
};
class ConcreteBuilder2 :public Builder
{
private:
Product* product = new Product();
public:
void BuildPartA()
{
product->Add("邮件X");
}
void BuildPartB()
{
product->Add("邮件Y");
}
Product* GetResult()
{
return product;
}
};
//指挥者
class Director
{
public:
void Construct(Builder *builder)
{
builder->BuildPartA();
builder->BuildPartB();
}
};
//main 生成一个指挥者
Director* director = new Director();
//初始化具体实现类
Builder* b1 = new ConcreteBuilder1();
Builder* b2 = new ConcreteBuilder2();
//指挥构造
director->Construct(b1);
//获取结果、展示
Product *p1 = b1->GetResult();
p1->Show();
//指挥构造
director->Construct(b2);
//获取结果、展示
Product* p2 = b2->GetResult();
p2->Show();
建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。
观察者模式
双向耦合的代码
//.h
class StockObserver;
//观察者
class Secretary {
private:
//列表
list<StockObserver*> observer;
string action;
public:
string SecretaryAction;
void Attach(StockObserver* observer);
string getSecretaryAction()const;
void setSecretaryAction(const string SecretaryAction);
void Notify();
};
//被观察者
class StockObserver {
private:
string name;
Secretary* sub;
public:
StockObserver(string name, Secretary* sub)
{
this->name = name;
this->sub = sub;
}
void Update()
{
cout << sub->SecretaryAction << " " << name << " 收到通知" << endl;
}
};
//.cpp
void Secretary::Attach(StockObserver* observer)
{
this->observer.push_back(observer);
}
string Secretary::getSecretaryAction() const
{
return SecretaryAction;
}
void Secretary::setSecretaryAction(const string SecretaryAction)
{
this->SecretaryAction = SecretaryAction;
}
void Secretary::Notify()
{
for (StockObserver* o : observer)
{
o->Update();
}
}
//main
//通知者
Secretary* tongzizhe = new Secretary();
//被通知者
StockObserver* t1 = new StockObserver("张三", tongzizhe);
StockObserver* t2 = new StockObserver("李四", tongzizhe);
//通知者记录被通知者
tongzizhe->Attach(t1);
tongzizhe->Attach(t2);
//下发通知
tongzizhe->setSecretaryAction("玩家");
tongzizhe->Notify();
这是一份双向耦合的代码,观察者要添加被观察者,被观察者要观察者的状态。
解耦实践一
//抽象观察者
class Observer {
protected:
string name;
Secretary* sub;
public:
Observer(string name, Secretary* sub)
{
this->name = name;
this->sub = sub;
}
virtual void Update() = 0;
};
//两个具体类
class StockObserver:public Observer {
public:
StockObserver(string name, Secretary* sub) : Observer(name,sub)
{
}
void Update()
{
cout << sub->SecretaryAction << " " << name << " 收到通知" << endl;
}
};
class NBAObserver :public Observer {
public:
NBAObserver(string name, Secretary* sub) : Observer(name, sub)
{
}
void Update()
{
cout << sub->SecretaryAction << " " << name << " 收到通知" << endl;
}
};
//观察者类--通知者
class Secretary {
private:
//列表
list<Observer*> observer;
string action;
public:
string SecretaryAction;
void Attach(Observer* observer);
void Detach(Observer* observer);
string getSecretaryAction()const;
void setSecretaryAction(const string SecretaryAction);
void Notify();
};
//main
//通知者
Secretary* tongzizhe = new Secretary();
//被通知者
Observer* t1 = new StockObserver("张三", tongzizhe);
Observer* t2 = new NBAObserver("李四", tongzizhe);
//通知者记录被通知者
tongzizhe->Attach(t1);
tongzizhe->Attach(t2);
//下发通知
tongzizhe->setSecretaryAction("玩家");
tongzizhe->Notify();
观察者已经抽象,但是通知者却没有,因为存在多个通知者的情况。
解耦实践二
//抽象被通知者
class Observer {
protected:
string name;
Subject* sub;
public:
Observer(string name, Subject* sub)
{
this->name = name;
this->sub = sub;
}
virtual void Update() = 0;
};
//抽象通知者
class Subject {
public:
virtual void Attach(Observer* observer) = 0;
virtual void Detach(Observer* observer) = 0;
virtual void Notify() = 0;
virtual string getSecretaryAction()const = 0;
virtual void setSecretaryAction(const string SecretaryAction) = 0;
private:
string SecretaryAction;
};
//实例通知者类1
class Secretary:public Subject {
private:
//列表
list<Observer*> observer;
string action;
string SecretaryAction;
public:
void Attach(Observer* observer);
void Detach(Observer* observer);
string getSecretaryAction()const;
void setSecretaryAction(const string SecretaryAction);
void Notify();
};
//实例通知者类2
class Boss : public Subject {
//列表
list<Observer*> observer;
string action;
string SecretaryAction;
public:
void Attach(Observer* observer);
void Detach(Observer* observer);
string getSecretaryAction()const;
void setSecretaryAction(const string SecretaryAction);
void Notify();
};
//实例被通知者类1
class StockObserver:public Observer {
public:
StockObserver(string name, Subject* sub) : Observer(name,sub)
{
}
void Update()
{
cout << sub->getSecretaryAction() << " " << name << " 收到通知" << endl;
}
};
//实例被通知者类2
class NBAObserver :public Observer {
public:
NBAObserver(string name, Subject* sub) : Observer(name, sub)
{
}
void Update()
{
cout << sub->getSecretaryAction() << " " << name << " 收到通知" << endl;
}
};
//main
//通知者
Secretary* tongzizhe1 = new Secretary();
Boss* tongzizhe2 = new Boss();
//被通知者
StockObserver* t1 = new StockObserver("张三", tongzizhe1);
NBAObserver* t2 = new NBAObserver("李四", tongzizhe1);
//通知者记录被通知者
tongzizhe1->Attach(t1);
tongzizhe1->Attach(t2);
tongzizhe2->Attach(t1);
tongzizhe2->Attach(t2);
//下发通知
tongzizhe1->setSecretaryAction("玩家");
tongzizhe1->Notify();
tongzizhe2->setSecretaryAction("BOSS");
tongzizhe2->Detach(t1);
tongzizhe2->Notify();
观察者模式又叫做发布-订阅模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
总结
//抽象通知者 一般用一个抽象类或者一个接口实现。可以增加和删除观察者对象。
class Subject {
public:
void Attach(Observer* observer)
{
this->observers.push_back(observer);
}
void Detach(Observer* observer)
{
this->observers.remove(observer);
}
void Notify()
{
for (Observer* o : observers)
{
o->Update();
}
}
private:
list<Observer*> observers;
};
//抽象观察者 为所有的实例定义一个接口,在得到主题的通知时更新自己。
class Observer {
public:
virtual void Update() = 0;
};
//-------------------------------
//具体通知者类,将有关状态存入具体观察者对象,
class ConcreteSubject :public Subject {
private:
string subjectState;
public:
void setSubjectState(string subjectState)
{
this->subjectState = subjectState;
}
string getSubjectState()const
{
return subjectState;
}
};
//具体观察者
class ConcreteObserver :public Observer {
public:
ConcreteObserver(ConcreteSubject* subject, string name)
{
this->subject = subject;
this->name = name;
}
void Update()
{
observerState = subject->getSubjectState();
cout << "观察者 " << name << " 的新状态是 " << observerState << endl;
}
void setSubject(ConcreteSubject* subject)
{
this->subject = subject;
}
ConcreteSubject* getSubject()
{
return subject;
}
private:
string name;
string observerState;
ConcreteSubject* subject;
};
//main
ConcreteSubject* s = new ConcreteSubject();
s->Attach(new ConcreteObserver(s, "X"));
s->Attach(new ConcreteObserver(s, "Y"));
s->Attach(new ConcreteObserver(s, "Z"));
s->setSubjectState("ABC");
s->Notify();
为什么使用观察者?
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间一致性。我们不希望为了一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知。Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道。并且任何一个具体观察者不知道也不需要知道其他观察者的存在。
什么时候使用?
当一个对象的改变需要同时改变其他对象的时候。而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。当一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立的改变和复用。
总的来说,观察者模式所做的工作其实就是在接触耦合。让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。
观察者模式有什么不足点?
每个具体的观察者,它的“更新”不一定调用,比如有的要关闭或者隐藏等,所以需要用到时间委托实现。