[Arch] 02. Design principle and Software Pattern

软件设计的七大原则html

六大设计原则(C#)【有代码实例讲解,有空看一下】数据库

 

  

软件设计的若干原则


前五个重要原则

1、SOLID设计

Figure, 重要的前五个原则编程

 

2、原则详解

(1) 单一职责原则 (Simple responsibility pinciple SRP)

类的设计趋向于:Use Case Diagram --> (derived) --> Detail设计模式

就一个类而言,应该仅有一个引发它变化的缘由,若是你能想到多于一个的动机去改变一个类,那么这个类就具备多于一个的职责.应该把多于的指责分离出去,分别再建立一些类来完成每个职责. 安全

 

(2) 开-闭原则 (Open-Closed Principle, OCP)

/* Software entities should be open for extension, but closed for modification */架构

  反面例子:Dependency: 做为参数,做为局部变量,调用静态方法。框架

  改进方式:增长抽象类或者接口,以及set方法。函数

再设计一个模块的时候,应当使这个模块能够在不被修改的前提下被扩展.post

换言之,应当能够在没必要修改源代码的状况下改变这个模块的行为,在保持系统必定稳定性的基础上,对系统进行扩展。性能

这是面向对象设计(OOD)的基石,也是最重要的原则。

 

(3) 里氏代换原则 (Liskov Substitution Principle, LSP)

[replace A with B 用B来代替A]

[substitute A for B 用A来代替B (或者A substitute for B)]

  Derived Class 需严格成为 Base Class 的子类型。 

首先针对基类编程,在具体实现  或程序运行时再肯定具体子类。 <-- 实现开闭原则的重要基础

应当尽可能从抽象类继承,而不从具体类继承,

通常而言,若是有两个具体类A, B有继承关系,那么一个最简单的修改方案是创建一个抽象类C,而后让类A和B成为抽象类C的子类.

即若是有一个由继承关系造成的登记结构的话,那么在等级结构的树形图上面全部的树叶节点都应当是具体类;而全部的树枝节点都应当是抽象类或者接口.

  

(4) 接口隔离原则(Interface Segregation Principle, ISP)

接口杜绝臃肿,以避免空方法实现。

倾向瘦接口

 

(5) 依赖倒置原则 (Dependence Inversion Principle)

除去set方法,也可采用读取配置文件来选择类的调用。<-- 实现开闭原则的重要手段

A.高层次的模块不该该依赖于低层次的模块,他们都 应该依赖于抽象
B.抽象不该该依赖于具体实现,具体实现 应该依赖于抽象

接口与抽象的区别就在于抽象类能够提供某些方法的部分实现,而接口则不能够,这也大概是抽象类惟一的优势。

若是向一个抽象类加入一个新的具体方法,那么全部的子类型一会儿就都获得获得了这个新的具体方法,而接口作不到这一点。

 

 

第六个原则

1、另外一个原则

(*) 合成/聚合复用原则 (Composite/Aggregate Reuse Principle,CARP)

简短的表述:要尽可能使用合成/聚合,尽可能不要使用继承。

ref: 谈一谈本身对依赖、关联、聚合和组合之间区别的理解【有代码示范】

ref: 类与类之间的几种关系

 

[总结]

对于继承、实现这两种关系没多少疑问,它们体现的是一种类和类、或者类与接口间的纵向关系。其余的四种关系体现的是类和类、或者类与接口间的引用、横向关系,是比较难区分的,有不少事物间的关系要想准肯定位是很难的。前面也提到,这四种关系都是语义级别的,因此从代码层面并不能彻底区分各类关系,但总的来讲,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖

若 需使用一个类的方法,能够经过 继承 或者 聚合/组合

优前后者,下降耦合。

 

 

2、实例:DAO的实现

既然 getConnection() 可能会变化,那么其所在的类 不便成为基类(Base Class),

而后 采用 构造函数注入setter方法注入接口注入。从而注入不一样的数据库。

 

三种注入方法

Reference: Sprint IOC 三种注入方法

  • 控制反转 (Inverse Of Control) 

/* 难理解,往后再说 */

控制反转是一种将 组件依赖关系 的 建立和管理 置于程序外部的技术。
由容器控制程序之间的关系,而不是由代码直接控制。
因为控制权由代码转向了容器,因此称为反转。

 

Dependency Injection:两个对象之间的依赖关系在程序运行时由外部容器动态的注入依赖行为方式称为依赖注入 (DI) 。 DI 是 IOC 的一种形式。
依赖注入的三种实现类型:接口注入、 Setter注入和构造器注入。

接口注入
public
class ClassA {   private InterfaceB clzB;   public void doSomething()
  {     Ojbect obj
= Class.forName(Config.BImplementation).newInstance();     clzB = (InterfaceB)obj;     clzB.doIt()   }   …… }

 

set注入
public
class ClassA {   private InterfaceB clzB;   public void setClzB(InterfaceB clzB)   {     this. clzB = clzB;   }   …… }

 

构造器注入
public
class DIByConstructor { private final DataSource dataSource; public DIByConstructor(DataSource ds)
  {
this.dataSource = ds; } …… }

 

 

面向切面 (Aspect Oriented Programming)

???

/* implement */

 

 

第七个原则

(*) 迪米特法则 (Law of Demeter LoD) ,又叫作最少知识原则 (Least Knowledge Principle,LKP)

/* 一个软件实体应当尽量少地与其余实体发生相互做用 */

添加中间类来下降界面组件之间的耦合度.

一个对象应当对其余对象有尽量少的了了解,为了下降耦合度。

 

 

 

 

类间关系


Ref: 类与类之间的几种关系

1、继承关系

继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并能够增长它本身的新功能的能力。在Java中继承关系经过关键字extends明确标识,在设计时通常没有争议性。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指向父类,或者子接口指向父接口。 


2、实现关系

实现指的是一个class类实现interface接口(能够是多个)的功能,实现是类与接口之间最多见的关系。在Java中此类关系经过关键字implements明确标识,在设计时通常没有争议性。在UML类图设计中,实现用一条带空心三角箭头的虚线表示,从类指向实现的接口。 


3、依赖关系

【做为了参数而使用】

简单的理解,依赖就是一个类A使用到了另外一个类B,而这种使用关系是具备偶然性的、临时性的、很是弱的,可是类B的变化会影响到类A。好比某人要过河,须要借用一条船,此时人与船之间的关系就是依赖。表如今代码层面,为类B做为参数被类A在某个method方法中使用。在UML类图设计中,依赖关系用由类A指向类B的带箭头虚线表示。 


4、关联关系

关联体现的是两个类之间语义级别的一种强依赖关系,好比我和个人朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,通常是长期性的,并且双方的关系通常是平等的。关联能够是单向、双向的。表如今代码层面,为被关联类B以类的属性形式出如今关联类A中,也多是关联类A引用了一个类型为被关联类B的全局变量。在UML类图设计中,关联关系用由关联类A指向被关联类B的带箭头实线表示,在关联的两端能够标注关联双方的角色和多重性标记。 


5、聚合关系     

聚合是关联关系的一种特例,它体现的是总体与部分的关系,即has-a的关系。此时总体与部分之间是可分离的,它们能够具备各自的生命周期,部分能够属于多个总体对象,也能够为多个总体对象共享。好比计算机与CPU、公司与员工的关系等,好比一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。表如今代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,聚合关系以空心菱形加实线箭头表示。 


6、组合关系     

组合也是关联关系的一种特例,它体现的是一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它一样体现总体与部分间的关系,但此时总体与部分是不可分的,总体的生命周期结束也就意味着部分的生命周期结束,好比人和人的大脑。表如今代码层面,和关联关系是一致的,只能从语义级别来区分。在UML类图设计中,组合关系以实心菱形加实线箭头表示。 

 

 

 

 

软件模式


软件模式: 设计模式体系结构模式、分析模式、过程模式等。 

体系结构模式

ANSIIEEEStd1471一200对体系结构的定义:一个系统的基本组织,表现为系统的组件、组件之间的相互关系、组件和环境之间的相互关系以及设计和进化的原则。

 

黑板模式

黑板模式是一种经常使用的架构模式,应用中的多种不一样数据处理逻辑相互影响和协同来完成数据分析处理。

“就好像多位不一样的专家在同一黑板上交流思想,每一个专家均可以得到别的专家写在黑板上的信息,同时也能够用本身的分析去更新黑板上的信息,从而影响其它专家。”

 

数据库模式

利用 数据库充当黑板,不一样的应用共享数据库中信息,而且能够更新数据信息。这也是最多见的实现方式。
 
特色:
1 便于实现信息的查询,筛选和统计,这方面关系数据库提供了SQL 92的强大支持。
2 不能用于 较高实时性要求的环境,这种实现是工做在“拉模式”下的,而且高频率的访问数据库会致使严重的 系统性能问题
 
 

发布—订阅模式 (难点)

这种实现方式一般采用 消息队列做为黑板,队列工做在主题模式(Topic),专家做为队列的订阅者,同时能够向队列发送消息,消息会被发送至全部订阅者。
 
订阅发布模式定义了一种一对多的依赖关系, 让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时,会通知全部订阅者对象,使它们可以自动更新本身的状态。
 
特色:
1 能够有效应用于实时性要求较高的系统,这种实现工做在“推模式”下。
2 难于实现信息的统计分析,不像实现方式一那样能够经过SQL支持,这些工做必须开发者本身完成。
 
 
 
 

 1) 一个 delegate对象一次能够搭载多个方法(methods),而不是一次一个。当咱们唤起一个搭载了多个方法(methods)的delegate,全部方法以其“被搭载到delegate对象的顺序”被依次唤起。

 2) 一个delegate对象所搭载的方法(methods)并不须要属于同一个类别。一个delegate对象所搭载的全部方法(methods)必须具备相同的原型和形式。然而,这些方法(methods)能够即有static也有non-static,能够由一个或多个不一样类别的成员组成。

 3) 一个delegate type的声明在本质上是建立了一个新的subtype instance,该 subtype 派生自 .NET library framework 的 abstract base classes Delegate 或 MulticastDelegate,它们提供一组public methods用以询访delegate对象或其搭载的方法(methods) ,与函数指针不一样,委托是面向对象、类型安全而且安全的。

 

 

 

为了实现P与S.P, S与S.P之间的解耦,咱们须要定义两个接口文件:

ISubscribe.cs
namespace TJVictor.DesignPattern.SubscribePublish { //定义订阅事件 public delegate void SubscribeHandle(string str); //定义订阅接口 public interface ISubscribe { event SubscribeHandle SubscribeEvent; } }
IPublish.cs namespace TJVictor.DesignPattern.SubscribePublish
{
    //定义发布事件
    public delegate void PublishHandle(string str);
    //定义发布接口
    public interface IPublish
    {
        event PublishHandle PublishEvent;

        void Notify(string str);
    }
}

 

而后咱们来设计订阅器。显然订阅器要实现双向解耦,就必定要继承上面两个接口,这也是我为何用接口不用抽象类的缘由(类是单继承)。

namespace TJVictor.DesignPattern.SubscribePublish { public class SubPubComponet : ISubscribe, IPublish { private string _subName; public SubPubComponet(string subName) { this._subName = subName; PublishEvent += new PublishHandle(Notify); } #region ISubscribe Members
           event SubscribeHandle subscribeEvent; event SubscribeHandle ISubscribe.SubscribeEvent { add { subscribeEvent += value; } remove { subscribeEvent -= value; } } #endregion

           #region IPublish Members
           public PublishHandle PublishEvent; event PublishHandle IPublish.PublishEvent { add { PublishEvent += value; } remove { PublishEvent -= value; } } #endregion

           public void Notify(string str) { if (subscribeEvent != null) subscribeEvent.Invoke(string.Format("消息来源{0}:消息内容:{1}", _subName, str)); }
} }

 

 接下来是设计订阅者S。S类中使用了ISubscribe来与S.P进行解耦。代码以下:

namespace TJVictor.DesignPattern.SubscribePublish
{
    public class Subscriber
    {
        private string _subscriberName;
        public Subscriber(string subscriberName)
        {
            this._subscriberName = subscriberName;
        }

        public ISubscribe AddSubscribe { set { value.SubscribeEvent += Show; } }
        public ISubscribe RemoveSubscribe { set { value.SubscribeEvent -= Show; } }

        private void Show(string str)
        {
            Console.WriteLine(string.Format("我是{0},我收到订阅的消息是:{1}", _subscriberName, str));
        }
    }
}

 

最后是发布者P,继承IPublish来对S.P发布消息通知。

namespace TJVictor.DesignPattern.SubscribePublish
{
    public class Publisher:IPublish
    {
        private string _publisherName;
        public Publisher(string publisherName)
        {
            this._publisherName = publisherName;
        }

        private event PublishHandle PublishEvent;
        event PublishHandle IPublish.PublishEvent
        {
            add { PublishEvent += value; }
            remove { PublishEvent -= value; }
        }

        public void Notify(string str)
        {
            if (PublishEvent != null)
                PublishEvent.Invoke(string.Format("我是{0},我发布{1}消息", _publisherName, str));
        }
    }
}

 

至此,一个简单的订阅发布模式已经完成了。下面是调用代码及运行结果。调用代码模拟了图2中的订阅发布关系,你们能够从代码,运行结果和示例图三方面对照着看。

 

#region TJVictor.DesignPattern.SubscribePublish

//新建两个订阅器
SubPubComponet subPubComponet1 = new SubPubComponet("订阅器1");
SubPubComponet subPubComponet2 = new SubPubComponet("订阅器2");

//新建两个发布者
IPublish publisher1 = new Publisher("TJVictor1");
IPublish publisher2 = new Publisher("TJVictor2");

//与订阅器关联 --> 订阅器 监听 发布者?
publisher1.PublishEvent += subPubComponet1.PublishEvent;
publisher1.PublishEvent += subPubComponet2.PublishEvent;
publisher2.PublishEvent += subPubComponet2.PublishEvent;

//新建两个订阅者
Subscriber s1 = new Subscriber("订阅人1");
Subscriber s2 = new Subscriber("订阅人2");

//进行订阅
s1.AddSubscribe = subPubComponet1;
s1.AddSubscribe = subPubComponet2;
s2.AddSubscribe = subPubComponet2;

/***********************************************************/

//发布者发布消息
publisher1.Notify("博客1");
publisher2.Notify("博客2");

//发送结束符号
Console.WriteLine("".PadRight(50,'-'));

//s1取消对订阅器2的订阅
s1.RemoveSubscribe = subPubComponet2;

//发布者发布消息
publisher1.Notify("博客1");
publisher2.Notify("博客2");

//发送结束符号
Console.WriteLine("".PadRight(50, '-'));

#endregion


#region Console.ReadLine();
Console.ReadLine();
#endregion

  

模型-视图-控制(MVC:Model-View-Controller)

  在知足对界面要求的同时,如何使软件的计算模型独立于界面的构成。

模型部件是软件所处理问题逻辑在独立于外在显示内容和形式状况下的内在抽象,封装了问题的核心数据、逻辑和功能的计算关系,他独立于具体的界面表达和I/O操做。
 
视图部件把表示模型数据及逻辑关系和状态的信息及特定形式展现给用户。它从模型得到显示信息,对于相同的信息能够有多个不一样的显示形式或视图。
 
控制部件是处理用户与软件的交互操做的,其职责是控制提供模型中任何变化的传播,确保用户界面于模型间的对应联系;它接受用户的输入,将输入反馈给模型,进而实现对模型的计算控制,是使模型和视图协调工做的部件。一般一个视图具备一个控制器。
 
模型、视图与控制器的分离,使得一个模型能够具备多个显示视图。若是用户经过某个视图的控制器改变了模型的数据,全部其它依赖于这些数据的视图都应反映到这些变化。所以,不管什么时候发生了何种数据变化,控制器都会将变化通知全部的视图,致使显示的更新。这其实是一种模型的变化-传播机制。

 

 相似的结构模式

还有PAC(Presentation-Abstraction-Control)、Forward-Receiver、Publisher-Subscriber、各种可视化用户界面控件等。

 

 

分析模式

Reference: 软件分析模式的形式化研究, 钟琪, 西南师范大学 

分析模式是更高层次的抽象。与测试模式不一样,分析模式不反应实际的软件实现,而是体现行业业务过程的概念结构。

按用途能够划分为:Accountability, Observations and measurements, Observations for Corporate finance, Referring to Objects, Inventory, Planning, trading.

 

Example: Party in Accountability

 

 

过程模式

Reference: http://www.cnblogs.com/houleixx/archive/2009/10/20/software-engineering-process-model.html 

软件过程是为了得到高质量软件所须要完成的一系列任务的框架,它规定了完成各项任务的工做步骤。

一般使用生命周期模型简洁地描述软件过程。生命周期模型规定了把生命周期划分红哪些阶段及各个阶段的执行顺序,所以,也称为过程模型。

常见的过程模型有瀑布模型快速原型模型增量模型螺旋模型喷泉模型等。

 

 

设计模式

设计模式是一套被反复使用、多数人知晓的、通过分类编目的、代码设计经验的总结,使用设计模式的目的是提升代码的可重用性,让代码更容易被他人理解,并保证代码可靠性。它是代码编制真正实现工程化。

详见以后的篇章,加油。

知名博客:http://www.javashuo.com/article/p-aljiukeo-gd.html

菜鸟教程:http://www.runoob.com/design-pattern/design-pattern-tutorial.html

 

End.

相关文章
相关标签/搜索