设计模式

设计模式六大原则

  • 单一职责原则:一个类,或者一个接口,最好只做一件事情,当发生变化时,他只能受到单一的影响;因为职责过多,可能引起变化的原因将会很多,这样导致职责和功能上的依赖,将严重影响其内聚性和耦合度,混乱由此而生。

  • 开闭原则:开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这

  • 里氏代换原则:里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

  • 依赖倒转原则:这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。

  • 接口隔离原则:这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

  • 迪米特原则(最少知道原则):为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。System.out.print()就是不符合这个原则。

  • 合成复用原则:原则是尽量使用合成\/聚合的方式,而不是使用继承。可有可无

代理模式

  • 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
  • 举例子:Thread其实实现了Runnable接口,但是它还干了许多Runnable接口没有干的事情,它先完成比线程主体更多的操作,比如分配CPU资源,线程是否启动等等,从类关系上看是典型的代理模式。

策略模式

  • 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。将算法的责任委派给不同的对象处理,在比较和排序时候经常用到。
  • 举例子:java的自定义类型内部新建一个内部类,有name和id两个属性,为了比较两个自定义类型,实现compartor接口,而不是直接重写comparable接口,在调用sort()函数的时候,可以把这个内部类直接传给sort()函数,这样就可以避免重写compareTo()方法,只要写两个内部类实现comparator接口即可。

单例模式

  • 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例
  • 应用场景:主要用在资源共享,控制资源之间交流 1.数据库连接池 2.日志应用 3.应用配置 4.线程池

单例模式实现:

  • 懒汉模式(懒加载):首先将构造函数设成private型,定义一个static变量来储存实例,调用getInstance方法获得实例,方法内部判断实例是否已经建立,没有就建一个,否则直接返回已有实例

  • 饿汉模式:定义变量的时候直接初始化。

  • 线程安全:懒汉模式不是线程安全的,因为可能有两个线程同时判断出对象没有实例化,于是创建了两个实例,饿汉模式一开始就初始化了实例,所以始终只有一个,不需要再创建

  • 实例化时机不同:懒汉模式获取的时候才实例化,饿汉定义变量的时候就实例化了

  • 延迟加载:懒汉模式需要的时候才创建,体现了延迟加载,(可用于缓存,实例就是缓存,有了就不再往缓存立方,没有才放)

  • 双重加锁:double-check:懒汉模式实现线程安全,每次获取实例的时候都需要加锁同步,影响效率,所以在外面在加一层判断,对象是否实例化,如果已经实例化过了就不需要再进里面去加锁同步了,(变量要定义成volatile类型)这还不是线程安全的?该还有将instance加个关键字volatile,不然的话编译重排序可能造成还没初始化完成就已经完成对象引用的复制,但是此时对象还没有初始化完毕。饱汉模式的区别volatile内存模型防止被优化

  • 枚举实现单例最好

  • 一种是通过枚举,一种是通过静态内部类

装饰模式

  • 在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。就是把想要包装的类,通过作为初始化参数传递给装饰类,然后装饰类给他加了一些功能。
  • Java中的打印流,PrintStream类PrintWriter类就用到了装饰模式,它本身实现的就是PrintStream(OutputStream),它所要干的事情就是构造函数里的OutputStream要干的事情,把数据传入到输入流当中,但是如果直接用OutputStream的话只能用write()方法,并请只能写byte类型,感觉很苦逼,所以它用PrintStream类来装饰(包装)了一下OutputStream类,这样它就可以更加方便的使用了,比如可以直接调用print();println();各种函数往流里面写东西。
  • ObjectOutputStream类就采用了装饰者模式,并要求通过另一个OutputStream从物理上写入序列化数据。ObjectOutputStream类包含了覆盖所有原始类型的方法,以及一个使用与引用类型的方法,通过这些方法可以将对应类型的值写入流中。

工厂模式

  • 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
  • 最主要的作用是解耦和,通过父类引用创建对象。可以利用反射机制实现工厂模式。

原型模式

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

原型模式 其实就是从一个对象再创建另外一个可定制的对象,并且不需要知道任何创建的细节。

JAVA原型模式是实现cloneable接口,并且重写clone()方法。分为浅复制和深复制。 PS:深拷贝与浅拷贝问题中,会发生深拷贝的有java中的8中基本类型以及他们的封装类型,另外还有String类型。其余的都是浅拷贝。

原型模式的优点及适用场景

使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。

使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。

因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

模板方法模式

定义一个操作中的算法的股价,而将一些步骤延迟到子类中。模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。子类替换掉父类中的抽象方法。

优点:模板方法模式是通过把不变行为搬到超类,去除子类中的重复代码来体现它的优势,提供了一个很好的代码复用平台。当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。

results matching ""

    No results matching ""