面向对象的七大设计原则并不孤立存在,而是相互依赖、相互补充,设计模式就是根据面向对象的七大原则总结出来的。
1. 单一职责原则
类的职责要单一,不能将太多的职责放在一个类中。一个对象应该只包含单一的职责,并且该职责应被完整的封装在一个类中。
核心精神:就一个类而言,应该仅有一个引起它变化的原因。
分析:T负责两个不同的职责:职责P1,职责P2。当职责P1需求发生改变而需要修改T时,有可能会导致原本运行正常的职责P2功能发生故障。
一个类(大到模块、小到方法)承担的职责越多,被复用的可能性就越小。而且一个类承担的职责过多,就会发生职责的耦合,当其中一个职责发生改变时,可能会影响其他职责的运作。
类的职责主要包括两个方面:数据职责和行为职责,数据职责通过其属性来体现,行为职责通过其方法来体现。
单一职责原则是实现高内聚、低耦合的指导方针,这就需要程序员发现类的不同职责并将其分离,而发现类的多重职责需要程序员具备较强的分析设计能力和相关重构经验。
解决方案:遵循单一职责原则。分别建立两个类T1、T2,使得T1完成职责P1功能,T2完成职责P2功能。这样,修改类T1时,不会使得职责P2发生故障。
单一职责原则的好处
降低了类的复杂性,提高了代码的可读性,降低了变更引起的风险。
编程时,要在类的职责分离上多思考,做到单一职责,这样代码才易维护、易扩展、易复用。
整合的思想在编程中尤为重要,手机整合DV,DC,MP3等。
简单的单一职责案例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式案例2
{
//负责陆地生物的行为职责
public class Terrestrial
{
public void Breathe(string animalName)
{
Console.WriteLine(animalName+"呼吸空气");
}
};
//负责水生生物的行为职责
public class Aquatic
{
public void Breathe(string animalName)
{
Console.WriteLine(animalName+"呼吸水");
}
}
class Program
{
static void Main(string[] args)
{
Terrestrial terrestrial = new Terrestrial();
terrestrial.Breathe("牛");
terrestrial.Breathe("羊");
terrestrial.Breathe("猪");
Aquatic aquatic = new Aquatic();
aquatic.Breathe("鱼");
Console.Read();
}
}
}
对简单的单一职责案例优化
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 设计模式案例
{
public class Animal
{
public void Breathe(string animalName)
{
if ("fish".Equals(animalName))
{
Console.WriteLine(animalName+"呼吸水");
}
else
{
Console.WriteLine(animalName+"呼吸空气");
}
}
}
internal class Program
{
static void Main(string[] args)
{
Animal animal=new Animal();
animal.Breathe("牛");
animal.Breathe("猪");
animal.Breathe("猪");
animal.Breathe("鱼");
Console.ReadLine();
}
}
}
对简单的单一职责案例再优化
namespace 设计模式案例3
{
/*虽然该类看上去违背了类的单一职责原则,但是在方法层面上职责是单一的
单一职责原则并不是绝对的
*/
public class Animal
{
public void Breathe01(string animalName)
{
Console.WriteLine(animalName+"呼吸空气");
}
public void Breathe02(string animalName)
{
Console.WriteLine(animalName+"呼吸水");
}
}
internal class Program
{
static void Main(string[] args)
{
Animal animal = new Animal();
animal.Breathe01("牛");
animal.Breathe01("牛");
animal.Breathe02("鱼");
Console.Read();
}
}
}
我对于单一职责的反思
单一职责原则的核心思想是:一个类,最好只做一件事,只有一个引起它变化的原因。
单一职责在某种意义是高内聚、低耦合在面向对象原则上的引申,其中将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
若职责过多,可能引起变化的原因就越多,这就会导致职责依赖,相互之间产生影响,从而极大地损伤其内聚性和耦合度。
单一职责通常意味着单一的功能,因此不要为类实现过多的功能点,以保证实体只有一个引起它变化的原因。
尽管如此,单一职责原则并不是绝对的,因为有职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。比如:类T只负责一个职责P,这样是符合单一职责原则的。但是由于需求变更,需要将职责P细分为粒度更细的职责P1,P2,这时如果要使程序遵循单一职责原则,需要将类T分解为T1和T2,分别负责P1、P2两个职责,但是在程序写好的情况下,这样做浪费时间,所以,可以简单的修改类T,用它来负责两个职责,虽然这样有悖单一职责原则。
-
开闭原则
软件实体对扩展是开放的,但对修改是关闭的,即在不修改一个软件实体的基础上去扩展其功能
-
里氏替换原则
在软件系统中,一个可以接收基类对象的地方必然可以接收一个子类对象。
-
依赖倒转原则
要针对抽象层编程,而不要针对具体类编程
-
接口隔离原则
使用多个专门的接口来取代一个统一的接口
-
合成复用原则
在系统中应该尽量多使用组合和聚合关联关系,尽量少使用,甚至不使用继承关系。
-
迪米特法则
一个软件实体对其他实体的引用越少越好,或者说如果两个类不必直接通信,那么这两个类就不应当发生直接的相互作用,而是通过引入一个第三者发生间接交互。