Java开发中的23+2种设计模式学习个人笔记(未完待续)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/eguid_1/article/details/51829203

注:个人笔记

一、设计模式分三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

另外两种:并发型模式和线程池模式

二、六大原则

1、开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。通俗一点就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们必须使用接口和抽象类。

2、里氏代换原则(Liskov Substitution Principle)

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

3、依赖倒转原则(Dependence Inversion Principle)

就是面向接口编程,依赖于抽象而不依赖于具体。

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

使用多个隔离的接口,比使用单个接口要好,就是降低类之间的耦合度。

设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便,即:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

实际上还是面向接口或抽象类编程思想,就是不需要知道实体的真正实现是怎么样的,只要知道这个接口能够实现这个功能就行了。

6、合成复用原则(Composite Reuse Principle)

尽量使用合成/聚合的方式,而不是使用继承。因为java不支持多继承,而且继承也会出现父-子类之间的紧耦合关系,所以最好是使用多个接口或者抽象类进行实现,而且还可以方便多个功能复用。

拿jdk举个例,比如:ArrayList类实现了Serializable, Cloneable, Iterable, Collection, List, RandomAccess几个接口,每个接口都实现了一些独有的功能,把它们合成在一起实现就是一个ArrayList类,就实现了序列化、克隆,迭代,排序等等功能,而变换这些接口的组合就可以实现很多比如ArrayDeque,LinkedList等等功能不同的实现类。

三、23+2种设计模式

1、工厂方法模式

工厂方法模式分三种:(1)普通工厂方法模式(2)多个工厂方法模式(3)静态工厂方法模式

(1)普通工厂方法模式

描述:建立一个工厂类,对实现同一个接口的类进行实例的创建

实现1:GamePlayer --->实现play()方法

接口:Player--->play() 方法 {

实现2:BallPlayer --->实现play()方法

工厂类:PlayerFactory----> product()方法(用于生成player接口的两个实现类)

代码实现:

public class PlayerFactory{

public Player product(String type){

//根据type参数判断是哪一个实现类并返回创建的实例,哪个都不是就返回null

return "gamePlayer".equals(type)?new BallPlayerImpl ():("ballPlayer".equals(type)?new GamePlayerImpl():null);

}

}

(2)多个工厂方法模式

描述:多个工厂模式就是在工厂模式的基础上去除了字符串判断,给每个实现类都创建一个方法

工厂类:

PlayerFactory--->productGame()方法(用于生成GamePlayer实现类);productBall()方法(用于生成BallGamer实现类)

代码实现:

public class PlayerFactory{

//生成GamePlayer实例

public Player productGame(){

return new GamePlayer();

}

//生成BallPlayer实例

public Player productBall(){

return new BallPlayer();

}

}

(3)静态工厂方法模式

描述:就是将工厂类里面的方法全部置为静态static方法,这样就不需要创建工厂类实例了,可以直接通过类名调用静态方法

代码实现:

public class PlayerFactory{

//生成GamePlayer实例

public static Player productGame(){

return new GamePlayer();

}

//生成BallPlayer实例

public static Player productBall(){

return new BallPlayer();

}

}

工厂方法模式总结:出现大量的实例需要被创建就可以使用工厂方法,比起前两种,静态工厂方法最为常用。

2、抽象工厂模式

描述:工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,就必须对工厂类进行修改,这违背了闭包原则;所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

通俗一点就是现在有个GamePlayerProduct工厂类,但是这个类中的product()方法只能创建GamePlayer类,要对工厂方法进行修改是违反闭包原则的(关于闭包,一般软件交付使用后是不允许修改的,只能在代码基础上增加),怎么办?在架构设计时就把这个问题考虑进去,使用工厂接口,有了这个接口,我们让GamePlayerProduct实现这个接口,以后如果有其它的类要创建工厂类也实现这个接口就解决了拓展性的问题。

代码实现:

工厂接口:

public interface PlayerFactory{

public Player product();

}

工厂类1:

public class GamePlayerFactory implements PlayerFactory{

@Override

public Player product(){

return new GamePlayer();

}

}

工厂类2:

public class BallPlayerFactory implementsPlayerFactory{

@Override

public Player product(){

return new BallPlayer();

}

}

总结:抽象工厂方法只有一个好处:提高程序的拓展性

3、单例模式

描述:什么事单例模式,单例模式就是该对象在一个jvm虚拟机中只存在一个实例。

在实际的应用中,频繁的创建对象和GC操作都是比较耗费系统资源的,所以使用单例能够提高应用的整体性能。

在有些应用中,必须使用单例才能够保证系统的正确运行。

单例其实就是私有化构造方法,然后通过静态方法对外提供创建好的实例

(1)、最简单的单例实例(最常用)

public class Singleton {

//静态对象

private static Singelton instance=new Singleton();

//私有化构造器,防止通过new创建实例(注:只能防止new创建,通过类反射可以调用私有构造器)

private Singleton(){}

//对外提供静态方法用于调用实例

public static Singleton getSingleton()

{

return instance;

}

}

或者通过静态块创建单例,效果跟上面一样

public class Singleton {

//静态对象

private static Singelton instance=null;

//静态块,只在类第一次被调用时才会加载静态块

static{

instance=new Singleton();

}

//私有化构造器,防止通过new创建实例(注:只能防止new创建,通过类反射可以调用私有构造器)

private Singleton(){}

//对外提供静态方法用于调用实例

public static Singleton getSingleton()

{

return instance;

}

}

(2)、为了提高运行效率,可以延迟创建对象

public class Singleton {

//静态对象

private static Singelton instance=null;

//私有化构造器,防止通过new创建实例(注:只能防止new创建,通过类反射可以调用私有构造器)

private Singleton(){}

//对外提供静态方法用于调用实例

public static Singleton getSingleton()

{

if(instance==null)

{

instance =new Singelton();

}

return instance;

}

}

这种方法只适合没有多线程的情况下,那么遇到多线程调用就需要加锁

public class Singleton {

//静态对象

private static Singelton instance=null;

//私有化构造器,防止通过new创建实例(注:只能防止new创建,通过类反射可以调用私有构造器)

private Singleton(){}

//对外提供静态方法用于调用实例

public static Singleton getSingleton()

{

//加个锁块即可,为什么不在方法上加synchronized,因为这个方法本身是没有多线程问题的,线程问题出在:判断是否为空和创建实例的时候,这时候如果不加锁,多个线程就会发生多次创建实例的问题。

synchronized (instance) {

if(instance==null)

{

instance =new Singelton();

}

}

return instance;

}

}

(3)、创建实例和获取实例分离设计

之所以会出现线程问题,就在于我们每次获取实例都要判断实例是否已经创建好,如果没有创建,就在该方法中创建一个实例,那么我们把创建实例这一步单独拿出来对外提供方法即可。这样就把线程问题解决了,但是复杂了外部调用方式,外部在调用的实例的时候就需要先调用getSingleton()判断取到实例是否为空,如果为空则再调用initSingleton()方法创建一个实例,然后再次getSingleton()获取实例。

public class Singleton {

//静态对象

private static Singelton instance=null;

//私有化构造器,防止通过new创建实例(注:只能防止new创建,通过类反射可以调用私有构造器)

private Singleton(){}

//初始化实例

public static synchronized void initSingleton()

{

if(instance==null)

{

instance =new Singelton();

}

}

//调用实例

public static Singleton getSingleton()

{

return instance;

}

}

4、建造者模式

工厂模式是创建单个类的模式,建造者模式就是把各个类整合起来创建复合对象。

(1)单个类的多个实例

public class Examples{

private List<Example> exampleList=new ArrayList<Example>();

//创建多个实例

public void productExamples(int num)

{

for(;num>0;num--)

{

exampleList.add(new Example());

}

}

public List<Example> getExamples()

{

return exampleList;

}

}

(2)多个类多实例

public class Examples{

private Map<String,Object> map=new HashMap<String,Object>(10);

//创建多个类实例

public void productExamples()

{

map.put("example1",new Example1());

map.put("example2",new Example2());

map.put("example3",new Example3());

map.put("example4",new Example4());

}

public Map<String,Object> getExamples()

{

return map;

}

}

5、原型模式

未完待续。。。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏高性能服务器开发

聊聊整体性学习方法

「整体性学习方法」是在一本叫做《如何高效学习》的书中看到的。这本书的作者是个老外,他用一年就学完了四年的麻省理工课程。而这本书正是其这一年来的学习心得,书中介绍...

13620
来自专栏Java架构沉思录

Skywalking之Java Agent基础

之前的文章提到,要用 Skywalking 监控一个应用,需要在其 VM 参数中添加 “-javaagent:skywalking-agent.jar”(省略s...

14120
来自专栏芋道源码1024

Elasticsearch 7.4.0 发布,分布式搜索和数据分析引擎

Elasticsearch 7.4.0 发布了,Elasticsearch 是一个分布式的 RESTful 风格的搜索和数据分析引擎。

14930
来自专栏光城(guangcity)

C++ STL源码剖析 tr1与std array

C++ tr1全称Technical Report 1,是针对C++标准库的第一次扩展。即将到来的下一个版本的C++标准c++0x会包括它,以及一些语言本身的扩...

12730
来自专栏梧雨北辰的开发录

iOS内存管理-基本概念整理

主要内容: 1.内存区域划分 2.内存管理/引用计数 3.MRC手动管理引用计数 4.ARC自动引用计数 5.内存泄漏问题 6.野指针问题

7520
来自专栏芋道源码1024

惊呆了,Spring Boot居然这么耗内存!

Spring Boot总体来说,搭建还是比较容易的,特别是Spring Cloud全家桶,简称亲民微服务,但在发展趋势中,容器化技术已经成熟,面对巨耗内存的Sp...

32010
来自专栏北京马哥教育

快速掌握一个语言最常用的50%

现在的开发工作要求我们能够快速掌握一门语言。一般来说应对这种挑战有两种态度:其一,粗粗看看语法,就撸起袖子开干,边查Google边学习;其二是花很多时间完整地把...

9620
来自专栏Java编程指南

工作了几年还不知道Java虚拟机?(图文详解JVM)

11720
来自专栏光城(guangcity)

STL 源码剖析之动态数组 vector

vector 的数据安排以及操作方式,与 array 非常相似。两者的唯一差别在于空间的运用的灵活性,array 是静态的,一旦配置了就不能改变,而 vecto...

11020
来自专栏Java帮帮-微信公众号-技术文章全总结

纳尼,Java 存在内存泄泄泄泄泄泄漏吗?

Java 最牛逼的一个特性就是垃圾回收机制,不用像 C++ 需要手动管理内存,所以作为 Java 程序员很幸福,只管 New New New 即可,反正 Jav...

8940

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励