设计模式分类及六大原则

news/2024/12/30 1:41:31/

一、设计模式的分类

创建型模式:
工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式:
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式行为模式:
策略模式、模板方法模式、观察者模式、责任链模式、迭代子模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

二、设计模式六大原则

1.开闭原则:
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。
所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。2.里氏替换原则:
该原则的核心思想就是在程序当中,如果将一个父类对象替换成它的子类对象后,该程序不会发生异常。这也是该原则希望达到的一种理想状态。
通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。
里氏代换原则是开闭原则的重要方式之一,由于使用父类对象的地方都可以使用子类对象,因此在程序中尽量使用父类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。3.依赖倒置原则:
高层模块不应该依赖低层模块,二者都应该依赖其抽象
抽象不应该依赖细节,细节应该依赖抽象
依赖倒转(倒置)的中心思想是面向接口编程
依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类
使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成4.接口隔离原则:
当一个接口太大时,我们需要将它分割成一些细小的接口,使用该接口的客户端只需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干不该干的事情,干该干的事请
在使用接口隔离原则时我们要控制接口的颗粒度,颗粒度不能太大,也不能太小。如果太小就会造成接口泛滥,不利于维护;
接口如果太大就会违背接口隔离原则,灵活性较差,使用起来不方便。一般来说接口中仅包含某业务模块的方法即可,不应该有其他业务模块的方法。5.单一职责:
对一个类而言,应该仅有一个引起它变化的原因。 如果存在多于一个动机去改变一个类,那么这个类就具有多于一个的职责,就应该把多余的职责分离出去,再去创建一些类来完成每一个职责。6.迪米特原则(最少知道原则):
一个对象应该对其他对象有最少的了解。通俗来说就是,一个类对自己需要耦合或者调用的类知道的最少,你类内部怎么复杂,我不管,那是你的事,我只知道你有那么多公用的方法,我能调用。
迪米特原则核心观念就是:类间解耦,弱耦合。
从迪米特法则的定义和特点可知,它强调以下两点:
从依赖者的角度来说,只依赖应该依赖的对象。
从被依赖者的角度说,只暴露应该暴露的方法。
迪米特法则要求限制软件实体之间通信的宽度和深度,正确使用迪米特法则将有以下两个优点:
降低了类之间的耦合度,提高了模块的相对独立性。
由于亲合度降低,从而提高了类的可复用率和系统的扩展性。

三、如何理解组合优于继承

假设我们要设计一个关于鸟的类。我们将“鸟”这样一个抽象的事物概念,定义为一个抽象类AbstractBird。所有更细分的鸟,比如麻雀、鸽子、乌鸦等,都继承这个抽象类。
我们知道,大部分鸟都会飞,那我们可不可以在 AbstractBird抽象类中,定义一个fly()方法呢?答案是否定的。尽管大部分鸟都会飞,但也有特例,比如鸵鸟就不会飞。
鸵鸟继承具有fly()方法的父类,那鸵鸟就具有“飞”这样的行为,这显然不对。如果在鸵鸟这个子类中重写fly() 方法,让它抛出UnSupportedMethodException异常呢?
虽然可以解决问题,但不优雅。因为除了鸵鸟之外,不会飞的鸟还有很多,比如企鹅。对于这些不会飞的鸟来说,全部都去重写fly()方法,抛出异常,完全属于代码重复。理论上这些不会飞的鸟根本就不应该拥有fly()方法,让不会飞的鸟暴露fly()接口给外部,增加了被误用的概率。
要解决上面的问题,就得让AbstractBird类派生出两个更加细分的抽象类:会飞的鸟类AbstractFlyableBird和不会飞的鸟类AbstractUnFlyableBird,让麻雀、乌鸦这些会飞的鸟都继承 AbstractFlyableBird,让鸵鸟、企鹅这些不会飞的鸟,都继承 AbstractUnFlyableBird 类
这样一来,继承关系变成了三层。但是如果我们不只关注“鸟会不会飞”,还要继续关注“鸟会不会叫”,将鸟划分得更加细致时呢?两个关注行为自由搭配起来会产生四种情况:会飞会叫、不会飞会叫、会飞不会叫、不会飞不会叫。如果继续沿用刚才的设计思路,继承层次会再次加深。
如果继续增加“鸟会不会下蛋”这样的行为,类的继承层次会越来越深、继承关系会越来越复杂。而这种层次很深、很复杂的继承关系,一方面,会导致代码的可读性变差。因为我们要搞清楚某个类具有哪些方法、属性,必须阅读父类的代码、父类的父类的代码……一直追溯到最顶层父类的代码。另一方面,这也破坏了类的封装特性,将父类的实现细节暴露给了子类。子类的实现依赖父类的实现,两者高度耦合,一旦父类代码修改,就会影响所有子类的逻辑。因此可以看出:继承最大的问题就在于:继承层次过深、继承关系过于复杂时会影响到代码的可读性和可维护性。复用性是面向对象技术带来的很棒的潜在好处之一。如果运用的好的话可以帮助我们节省很多开发时间,提升开发效率。但是,如果被滥用那么就可能产生很多难以维护的代码。作为一门面向对象开发的语言,代码复用是Java引人注意的功能之一。Java代码的复用有继承、组合以及委托三种具体的实现形式。
对于上面提到的继承带来的问题,可以利用组合(composition)、接口、委托(delegation)三个技术手段一块儿来解决。
接口表示具有某种行为特性。针对“会飞”这样一个行为特性,我们可以定义一个Flyable接口,只让会飞的鸟去实现这个接口。对于会叫、会下蛋这些行为特性,我们可以类似地定义Tweetable接口、EggLayable接口
不过,接口只声明方法,不定义实现。也就是说,每个会下蛋的鸟都要实现一遍layEgg()方法,并且实现逻辑几乎是一样的(可能极少场景下会不一样),这就会导致代码重复的问题。那这个问题又该如何解决呢?有以下两种方法。
1.使用委托:
针对三个接口再定义三个实现类,它们分别是:实现了fly()方法的 FlyAbility类、实现了tweet()方法的TweetAbility类、实现了layEgg()方法的 EggLayAbility类。然后,通过组合和委托技术来消除代码重复。
2.使用Java8的接口默认方法
在Java8中,我们可以在接口中写默认实现方法。使用关键字default定义默认接口实现,当然这个默认的方法也可以重写。继承主要有三个作用:表示is-a关系、支持多态特性、代码复用。而这三个作用都可以通过其他技术手段来达成。比如is-a关系,我们可以通过组合和接口的has-a关系来替代;多态特性我们也可以利用接口来实现;代码复用我们可以通过组合和委托来实现。所以,从理论上讲,通过组合、接口、委托三个技术手段,我们完全可以替换掉继承,在项目中不用或者少用继承关系,特别是一些复杂的继承关系。如何判断该用组合还是继承
尽管我们鼓励多用组合少用继承,但组合也并不是完美的,继承也并非一无是处。从上面的例子来看,继承改写成组合意味着要做更细粒度的类的拆分。这也就意味着,我们要定义更多的类和接口。类和接口的增多也就或多或少地增加代码的复杂程度和维护成本。
如果类之间的继承结构稳定(不会轻易改变),继承层次比较浅(比如,最多有两层继承关系),继承关系不复杂,我们就可以大胆地使用继承。反之,系统越不稳定,继承层次很深,继承关系复杂,我们就尽量使用组合来替代继承。除此之外,还有一些设计模式会固定使用继承或者组合。比如,装饰者模式(decorator pattern)、策略模式(strategy pattern)、组合模式(composite pattern)等都使用了组合关系,而模板模式(template pattern)使用了继承关系。

http://www.ppmy.cn/news/6850.html

相关文章

【leetcode】最大数

一、题目描述 给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。 注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。 示例 1: 输入:nums …

管理员权限功能和开机自启功能

前言 开机启动功能在Window下是很重要的一个功能,很多程序它都需要这样的功能 一.VS的配置选项(以管理员权限启动程序) 作用:用户在点击任务栏窗口等需要管理员权限时不会没有响应。 二.开机自启动(注册表&#xff…

【Educoder作业】CC++文件实训

【Educoder作业】C&C文件实训 拖了很久了,主要是当时没有完全理解 整个文件实训和之前的区别就在于,处理问题的时候我们的数据是存到了文件里或者我们希望把输出放到文件里。所以只需要解决文件输入和文件输出的问题即可。四个关卡相当于不同的手段&…

用uniapp实现teb切换

1.html <view><!-- tab栏切换动态改变激活样式 --><view class"nav"><view class"nav-list" v-for"(item,index) in list" :key"item.id" tap"changeAct(item)"><!-- 激活样式名字是红色 判断a…

李宪磊老师:人力资源一定要懂得八条人力资源管理定律

李宪磊老师:人力资源一定要懂得八条人力资源管理定律 作为人力资源&#xff0c;在职场上一定要知道的八条人力资源管理定律&#xff0c;看看您能知道多少&#xff0c;懂得这些定律&#xff0c;可以轻松的做好人力资源的工作&#xff0c;接下来和老师一起来学习下吧。 李宪磊老师…

OpManager 实时网络监控

网络是全球企业背后的基础。它在为您的员工提供行政服务以及为各大洲的客户提供服务方面发挥着关键作用。网络可帮助您将信息保存在一个集中位置 - 需要和限制所有其他入站请求的人员可以访问。那么&#xff0c;您如何提供持续的一流最终用户体验并维护快速发展的网络呢&#x…

大数据学习

优化: 按不同维度切分 ########## hadoop ########## 删除job hadoop job -kill job_xxx 折半查找(有序查找) 数据统计(hive) 数据过滤 同类汇聚 全局排序 容错框架 常见应用 从日志中找到某一个条件(时间,用户)数据 除去非法数据,保留合法数据 数据格式整理 混合日志,按…

【LeetCode】C语言实现---用队列实现栈用栈实现队列

目录&#x1f449;用队列实现栈&#x1f449;用栈实现队列&#x1f449;用队列实现栈 入口&#xff1a;OJ 题目描述&#xff1a; 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 em…