设计模式的第一课内容主要是介绍了什么是设计模式
Gof23种设计模式:历史性著作《设计模式:可复用面向对象软件的基础》一书中描述了23种经典面向对象设计模式,创立了模式在软件设计中的地位。该书四位作者被人们并称为Gang of Four (GoF),"四人组",该书描述的23种经典设计模式又被人们称为Gof23 种设计模式。
Gof23种设计模式并不意味着它表示了所有的面向对象的设计模式。面向对象的设计模式也并不意味着代表所有的设计模式。Gof23种设计模式只是设计模式的基础。
面向对象的设计模式主要解决的是"类与相互通信的对象之间的组织关系,包括它们的角色、职责、协作方式几个方面。面向对象设计模式的目的是应对变化,提高复用。面向对象的设计模式是与语言无关的。它可以通过各种面向对象的语言来实现如C++、C#、Java等。
我们在编程当中,都了解面向对象的语言的三大特性:封装、继承、多态。但是,仅仅通过面向对象的语言是不能够完全了解面向对象的设计的。面向对象语言的三大特性是为了实现面向对象而存在的,可以说面向对象是一篇文章,而三大特性是文章的写作技巧,这些写作技巧是为了写这篇文章而服务的。
那么这里有一个小示例,可以初步的了解面向对象设计。
... {
public abstract int GetSalary();
}
public class Engineer : Employee
... {
public override int GetSalary()
...{
//.....
}
}
public class Sales : Employee
... {
public override int GetSalary()
...{
//....
}
}
这里有一个Employee的抽象类,两个继承于Employee的派生类。GetSalary是一个抽象方法,这个方法的调用由派生类的类型决定。
我们现在还有一个工厂类
... {
public Employee GetEmployee(string EmployeeID)
...{
Employee objEmp = null;
switch (EmployeeID)
... {
case "Enginner":
objEmp = new Engineer();
break;
case "Sales":
objEmp = new Sales();
break;
}
return objEmp;
}
}
我们可以在程序种直接可以调用这个工厂类,来得到一个Employee
... {
EmployeeFactory objFactory = new EmployeeFactory();
Employee objEmp = objFactory.GetEmployee("Sales");
int Salary = objEmp.GetSalary();
}
如果这时候,我们的Employee类型增加了一个Worker。那么我们只需要新增一个Worker类,并仅仅需要修改GetEmployee的内部实现,其他的我们可以不作任何修改。Engineer和Sales类也可以不用修改。那么就达到了一个松耦合的目的。这里我们GetEmployee的参数可以是别的类型,比如说枚举,或整形等。
那么我们从宏观的层面看就是面向对象的构建方式更能适应软件的变化,能将变化所带来的影响减为最小。
从微观的层面来看面向对象的方式更强调各个类的"责任",新增员工类型不会影响原来员工类型的实现代码。实际上就是对原有代码的扩展。
对象是什么?
- 从概念层面讲,对象是某种拥有责任的抽象。
- 从规格层面讲,对象是一系列可以被其他对象使用的公共接口。
- 从语言实现层面来看,对象封装了代码和数据。
面向对象的设计原则:
- 针对接口编程,而不是针对实现编程:客户无需知道所使用对象的特定类型,只需要知道对象拥有客户所期望
的接口。 - 优先使用对象组合,而不是类继承:类继承通常为"白箱复用",对象组合通常为"黑箱复用"。继承在某种程度
上破坏了封装性,子类父类耦合度高;而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。 - 封装变化点:使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
- 使用重构得到模式:设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。提倡Refactoringto Patterns
- 单一职责原则:一个类应该仅有一个引起它变化的原因。
- 开放封闭原则:类模块应该是可扩展的,但是不可修改(对扩展开放,对更改封闭)
- Liskov 替换原则:子类必须能够替换它们的基类
- 依赖倒置原则:高层模块不应该依赖于低层模块,二者都应该依赖于抽象。 抽象不应该依赖于实现细节,实现细节应该依赖于抽象。
- 接口隔离原则:不应该强迫客户程序依赖于它们不用的方法。