热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

浅谈设计原则和设计模式

文章结构:1.前言2.设计原则3.设计模式3.1创建型模式3.2结构型模式3.3行为型模式前言设计原则和设计模式旨在帮助我们设
文章结构:
  1.前言
  2.设计原则       3.设计模式     3.1 创建型模式     3.2 结构型模式     3.3 行为型模式 
  前言

设计原则和设计模式旨在帮助我们设计出一个可复用、可扩展、可维护的应用.

 设计原则:设计OR重构系统的指导方针.

 设计模式:解决某类问题性质有效的方法.

设计原则和设计模式要实现的目标是:在需求变动或者系统升级时,尽可能少的改变代码,尽可能多的实现新的功能.

设计原则是设计模式的"背后的故事",要深入理解设计模式必先深入理解设计原则.


 

设计原则

1.开闭原则(Open Close Principle)

Open for extension, closed for modifications.

对扩展开放,对修改关闭.

可以说开闭原则是所有原则中最核心的原则,它的定义就是可扩展性可维护性最好的阐释. 

2.依赖倒置原则(Dependency Inversion Principle)

Depend upon Abstractions. Don’t depend upon concretions.

依赖倒置原则强调面向接口编程,依赖于抽象而非具体.依赖倒置原则和开闭原则是内在相通的,一个强调扩展,一个是实现扩展最常用的机制.

3.接口隔离原则(Interface Segregation Principle)

Many client-specific interfaces are better than one general-purpose interface.

接口隔离原则强调:一个接口对应一个客户,避免用一个接口提供给多个客户提供服务.一个接口对应一个客户,当该客户的需求变动时,只需要变动它所对应的接口.体现了高内聚低耦合的思想.

4.单一职责原则(Single Responsibility Principle)

A class should have only one reason to change.

就一个类而言,应该只有一个引起他变化的原因.

也就是说,不要把变化原因各不相同的职责放在一起,因为不同的变化会影响到不相干的职责。一个类尽量做到了功能单一,单一职能的不是说职能多了我们实现不了,是为了后期的测试维护,每个类的很单一,我们找错误的时候就可以一步到位.添加新的功能的时候,也不用牵扯到很多的类.

5.里氏替换原则(Liskov’s Substitution Principle)

Derived types must be completely substitutable for their base types.

子类型必须能够替换它们的父类型.这个原则是对继承的一个约束.里氏替换原则很好理解,举个例子:mysql的java驱动必须遵守jdbc规范.

引用一个非常好的总结:开闭原则是总纲,它告诉我们对扩展开放,对修改关闭;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们要在设计接口的时候要精简单一;单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系.

在实际开发中,我们应当尽量达到这些原则,而不是随时需要遵循这些原则.任何Java程序都有违反这些指导方针的地方.在合适的时候使用原则可以让我们的程序更富有弹性,但死板固执的应用这些原则会使程序更加复杂,事倍功半.


 

设计模式

   GOF将23设计模式种设计模式分为创建型、结构型、行为型3种类型.下面列出一些常见模式以及它们的应用实例.下面提到的模式实例的实现与书本上有所差距,相比模式的实现,我更关注的是模式的应用场景.

创建型模式

单例模式(Singleton):保证程序中一个类只有一个实例.

       应用实例:jdk中java.lang.Runtime

public class Runtime {
/**
* 类加载时初始化实例
*/
private static Runtime currentRuntime = new Runtime();
/**
* 提供获取实例的方法
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** 私有化构造函数 */
private Runtime() {}
// 剩下的方法
View Code

 工厂模式(Factory /Abstract Factory Pattern):用于封装对象的创建

    工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化哪一个类.

    抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类.

    个人感觉工厂方法模式和抽象工厂模式目的一样,只是表现形式不同,我也并不喜欢从概念上区分它们.jdk中的java.util.Calendar类就是工厂模式的典型应用:

   public static Calendar getInstance(TimeZone zone,
Locale aLocale)
{
return createCalendar(zone, aLocale);
}

private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
Calendar cal
= null;
String caltype
= aLocale.getUnicodeLocaleType("ca");
/** 根据不同条件创建不同的对象,典型的工厂模式应用场景 **/
if (caltype == null) {
if ("th".equals(aLocale.getLanguage())
&& ("TH".equals(aLocale.getCountry()))) {
cal
= new BuddhistCalendar(zone, aLocale);
}
else {
cal
= new GregorianCalendar(zone, aLocale);
}
}
else if (caltype.equals("japanese")) {
cal
= new JapaneseImperialCalendar(zone, aLocale);
}
else if (caltype.equals("buddhist")) {
cal
= new BuddhistCalendar(zone, aLocale);
}
else {
cal
= new GregorianCalendar(zone, aLocale);
}

return cal;
}
View Code

    工厂是很有威力的技巧,可以帮助我们针对抽象编程,而不要针对具体类编程. 

原型模式(Prototype):通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建更多的同类型的对象.

   应用实例:jdk中实现Prototype原型模式的类有很多,所有实现了java.lang.Cloneable接口的类都实现了原型模式.

建造者模式(Builder):封装复杂对象的创建过程.

   应用场景:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时;当构造过程必须允许被构造的对象有不同的表示时.

   应用实例:java.lang.StringBuffer,java.lang.StringBuilder


 

结构模式

适配器模式(Adapter)将一个类的接口转换成客户期望的另一个接口.适配器让原本不兼容的类可以合作无间.

应用实例:jdk中java.io.InputStreamReader和java.io.OutputStreamWriter

装饰者模式(Decorator):动态地为一个对象添加一些额外的行为职责,不改变类的源代码,给对象增加新的功能(OCP原则)

应用实例:jdk中java.io.InputStream和java.io.OutputStream的所有子类

桥接模式(Bridge):在软件系统中,某些类型由于自身逻辑,它具有两个或多个维度的变化,使用桥接模式可以应对这种多维度的变化.

桥接模式的意图: 将抽象部分与实现部分分离,使它们都可以独立的变化。

外观模式(Facade):提供一个统一的接口,用来访问子系统中的一群接口.外观定义了一个高层接口,让子系统更容易使用.

代理模式(Proxy):代理模式为一个对象提供一个代表(替身),用于控制该对象的访问.

应用实例:java.lang.reflect.Proxy和java.rmi

享元模式(Flyweight): 用共享的技术有效地支持大量细粒度的对象.

应用实例:java.lang.Integer(Boolean,Character,Byte,Short,Long)


 

行为模式

策略模式(Strategy):定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户.

应用实例:java.util.Comparator的compare()

模板模式(Template):定义了算法的步骤,把这些步骤的实现延迟到子类.模板方法模式提供了一种代码复用的重要技巧.

应用实例:java.lang.ClassLoader.loadClass();

观察者模式(Observer):在对象之间定义一对多依赖,当一个对象改变状态,依赖它的对象都会收到通知,并作出相应的操作.

应用实例:javax.servlet.http.HttpSessionBindingListener

状态模式(State):运行对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类.

迭代模式(Iterator):提供一种方法顺序访问一个集合对象中的各个元素,而又不暴露其内部的表示.

应用实例:java.util.Iterator

命令模式(Command):将一个请求封装成对象,这可以让你使用不同的请求、队列或者日志请求来参数化其他对象.命令模式也可以支持撤销操作.

应用实例:实现了java.lang.Runnable接口的子类

责任链模式(Chain of responsibility):当需要多个对象都有机会处理请求时可以考虑使用责任链模式.

应用实例: javax.servlet.Filter.doFilter()

解释器模式(Interpreter):Interpreter是一种特殊的设计模式,它建立一个解释器,对于特定的计算机程序设计语言,用来解释预先定义的语法.简单的说,解释器模式是一种简单的语法解释器.

应用实例:java.util.regex.Pattern java.text.Format的子类

中介者模式(Mediator):集中相关对象之间复杂的沟通和控制方式.

应用实例:java.util.Timer中的schelduleXXX()

备忘录模式(Memento):当你需要让对象返回之前的状态时,就是用备忘录模式.

应用实例:java.util.Date java.io.Serializable.在java中,可以考虑用序列化机制保存对象的状态.


推荐阅读
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • ShiftLeft:将静态防护与运行时防护结合的持续性安全防护解决方案
    ShiftLeft公司是一家致力于将应用的静态防护和运行时防护与应用开发自动化工作流相结合以提升软件开发生命周期中的安全性的公司。传统的安全防护方式存在误报率高、人工成本高、耗时长等问题,而ShiftLeft提供的持续性安全防护解决方案能够解决这些问题。通过将下一代静态代码分析与应用开发自动化工作流中涉及的安全工具相结合,ShiftLeft帮助企业实现DevSecOps的安全部分,提供高效、准确的安全能力。 ... [详细]
  • Java如何导入和导出Excel文件的方法和步骤详解
    本文详细介绍了在SpringBoot中使用Java导入和导出Excel文件的方法和步骤,包括添加操作Excel的依赖、自定义注解等。文章还提供了示例代码,并将代码上传至GitHub供访问。 ... [详细]
author-avatar
晨钟暮鼓芋
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有