设计模式六大原则,包括:
1.单一职责原则
2.里氏替换原则
3.依赖倒置原则
4.接口隔离原则
5.迪米特法则原则
6.开闭原则
下面分别来解释一下这六大原则。
单一职责原则主要是对类库与类库、类与类以及方法与方法之间的功能职责的描述——(个人理解为封装)
第一是类库的单一职责,从系统的解决方案分析,最传统的三层模式,UI层、业务逻辑层以及数据访问层,三层可以代表三个类库(dll)。每一个类库的职责分明,UI层用于管理和实现UI的实现,业务逻辑层用于管理和实现系统业务逻辑,数据访问层用于管理和实现数据库链接和访问。
第二是类的单一职责,系统每个类的理想状态是只描述一类的情况,例如Student类,只要描述Student属性,字段,方法等,不应该处理School或其他类的功能等,这样就可以避免在修改Student类时影响到School类的功能,或者是修改School类时影响到Student类的情况。
第三是方法的单一职责,例如Student类中有新增方法和修改方法,有的人比较喜欢写成一个方法,根据传入的某个参数来区分是新增还是更新,这就违背了单一职责,当你修改新增逻辑时,有可能会影响到修改逻辑,比如修改新增逻辑后,在某一步异常了,就会影响到你的更新逻辑,所以应该写新增和修改两个方法,把它们区分开,它们本来就是不相干的方法,不一样写在一起。总个来说,一个方法,最好是只能做一件事,让方法最小化,方便后期的维护。
里氏替换原则,任何使用父类的地方都可以用子类来代替——(个人理解为继承和多态)
下面用一段代码来解释一下,相对来说会直观一点:
下面的Chain类的实例,都可以用GuangDong类的实例来代替,子类都是可以替代父类的,但父类不能代替子类。
{
var chain = new Chian();
chain.SayHi();
chain = new GuangDong();
chain.SayHi();
}
public abstract class Human
{
public int Id { get; set; }
public string Name { get; set; }
public abstract void SayHi();
}
public class Chian:Human
{
public override void SayHi()
{
Console.WriteLine(string.Format("你好!!我是{0}",Name));
}
}
public class GuangDong : Chian
{
public void EatSomething()
{
Console.WriteLine("广东人喜欢吃东西!!");
}
}
程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了模块与模块间的耦合。——(个人理解为模块之间降低耦合度)
下面用图形来解释一下:左边是经典三层架构的简单示意图,UI层依赖业务逻辑层,业务逻辑层依赖数据访问层,属于高耦合,根据项目需求,如果替换掉数据访问层,那么整个业务逻辑层就要重写,对于一个公司项目了说,需要花费很大了人力和物力,很多公司都不愿意看到这样的情况,所以我们提倡额高内聚低耦合,为了实现低耦合,就出现了下图右边架构图,让项目UI层、业务逻辑层、数据访问层去依赖抽象,依赖接口来开发,即第三方容器(这种容器可以自己开发);当你要替换数据访问层时,对业务逻辑层来说完全不影响,替换了业务逻辑层,对UI层来说也不受影响的,实现了解耦。从层与层直接高度耦合变成了相互之间互不影响,降低了维护和修改成本。但是UI层、业务逻辑层和数据访问层还是依赖于抽象、接口,也是需要维护他们之间的关系,只不过是维护成本降低了,可以更灵活的维护,因此依赖关系发生了改变,实现的了依赖倒置。
客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上-(个人理解为,类只继承自己需要的功能的接口,自己不要的功能,不要继承)
比如你定义数据库访问的接口(IDBAccess),文件读取的接口(IFileRead),你实现一个数据库访问的类DBAccess,DBAccess类只要继承实现IDBAccess接口即可,不要继承IFileRead接口。
接口定义功能时,也不宜太多,也不宜太少;例如定义一个手机接口Iphone,Iphone接口包括:
public interface Iphone
{
void Call();
void Move();
void Music();
void Game();
void Pay();
}
假如Ipad只有Move、Music和Game的功能,这时Ipad就不能继承实现Iphone接口,应该把Iphone接口拆成两个两个接口,包含上面的上的所有的功能,尽可能的细化接口和实现接口,也能太细化接口,最好不要一个接口只有一个功能的设计,这样接口就太多,不易管理。
最少知道原则,即一个对象应当对其他对象有尽可能少的了解,不要和陌生人讲话,只和自己的朋友说话。
例如下图,部门总监,部门经理,项目经理,开发都各自代表一个类,部门总监管部门经理,部门经理管项目经理,项目经理管开发,他们不要跨级访问,这就是迪米特法则,尽可能少的访问与自己没有直接关系的类。
代码例子:
类与类之间关系层级分明,不出现跨级访问和操作
public class Staff
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Gender { get; set; }
}
public class Majordomo: Staff
{
public Manager Underling { get; set; }
public void Work()
{
Console.WriteLine($"部门经理{Underling.Name}和部门总监{this.Name}汇报工作");
}
}
public class Manager: Staff
{
public ProjectManager Underling { get; set; }
public void Work()
{
Console.WriteLine($"和项目小组组长{Underling.Name}计划排期项目时间进度");
}
}
public class ProjectManager: Staff
{
public Development Underling { get; set; }
public void Work()
{
Console.WriteLine($"给小组开发人员安排工作,被安排人名称为:{Underling.Name}");
}
}
public class Development: Staff
{
public void Develop()
{
Console.WriteLine("软件开发");
}
}
对于扩展开放,对修改关闭,意味着行为是可扩展的,当我们项目中的需求发生改变是,我们可以对现有模块进行扩展,不修改原有逻辑的情况下,实现新增需求的功能。
个人觉得开闭原则是设计模式六个原则中最虚的一个,基本是一个理想化的原则,也是最重要的一个原则,在我遇到的项目中,基本上很少能够完全符合这个设计原则。
设计模式的六大原则,纯属是我个人的理解,并且在实际工作项目中,很少有项目能够全部都遵循这六大原则,都有一定的取舍,要看具体的项目做相应的取舍和更偏向于哪个原则,类似于倾斜式的满足要求。