Java:一篇学好设计模式
什么是设计模式
简单理解,设计模式是前人多年写代码踩坑总结出来的优秀代码攻略,目的是减少大量无用代码,让项目更好维护
七大设计原则
接下来要讲的23种设计模式,但遵循下面的七大原则:
- 单一职责原则
2、接口隔离原则- 依赖倒置原则
4、里氏替换原则- 开闭原则
- 迪米特原则
- 合成复用原则
单一职责原则
单一职责原则,目的是每个类履行一种职责。好比一个人是医生,就好好干医生份内事,无需插手护士、保洁等和医生职责无关事
反例
比如说一个Person类,有工作work的方法:
public class Person{
public void work(String person){
System.out.println("职位为:"+ person + "的人正在工作");
}
}
这个Person,根据传的person能做各种职位的事,破坏了单一职责
正例
public interface Person{
public void work();
}
public class Doctor implement Person{
public void work(){
}
}
public class Teacher implement Person{
public void work(){
}
}
接口隔离原则
这个原则有点难讲,总结就是把接口拆成最简。
反例
有一个Person,有 fight打人、eat吃饭、work工作三个方法
public interface Person{
public void fight();
public void eat();
public void work();
}
现在有两个类:PersonA 和 PersonB 都实现了Person接口,实际上PersonA根本不需要打人,PersonB不需要工作。
正例
public interface Person1{
public void eat();
}
public interface Person2 extend Person1{
public void fight();
}
public interface Person3 extend Person1{
public void work();
}
拆成3个接口。如此一来,PersonA只需要实现Person3,PersonAB实现Person2
依赖倒置原则
依赖倒置原则,核心在于面向接口编程,传细节,定抽象。
反例
有个Person类,有send方法。
public class Person{
public void send(Email mail){
System.out.println(mail.getInfo());
}
}
这方法只能发邮件,那我发短信啥的就不行了
正例
定义3个接口
public interface Receiver{
public void getInfo();
}
public class Email implement Receiver{
public void getInfo(){
}
}
public class WeiXin implement Receiver{
public void getInfo(){
}
}
结果:
public class Person{
public void send(Receiver r){
System.out.println(mail.getInfo());
}
}
里氏替换原则
里氏替换原则,他的核心在于:尽量子类不用去重写父类的方法。
开闭原则
开闭原则,核心在于:对外允许拓展,对内拒绝修改。
什么意思呢?比如现在我给你了空的羽毛球圆筒,对外只需要装合适的羽毛球即可,对内是不拒绝像把羽毛球筒硬搞成方的
再举个例子,一些配置文件有些参数是固定好的,比如 server.port。对内可以编写自己的参数,对内是不允许修改server.port的参数名
迪米特原则
迪米特原则,被依赖的类尽量让依赖类知道的内部实现细节尽量少,总结就是降低耦合
合成复用原则
合成复用原则,当使用另一个类的方法时,尽量使用聚合的方式,减少使用继承。
这个比较好理解,现在有A类有个A1方法,B想要使用A1。不好的做法就是B去继承A,然后就有A1方法。推荐是B里引入A,然后调用A去用A1
设计模式
设计模式可分为3种类型,下面列举需要重点掌握的设计模式
创建型模式:单例模式,工厂模式,原型模式,建造者模式
结构型模式:适配器模式,装饰模式,代理模式
行为型模式:观察者模式
单例模式
单例模式,要求在整个应用中一个类只有一个对象实例。
刚开始此模式,懒汉和饿汉式的单例代码比较经典,大家有空去看下。
然后在spring最常见的单例就是我们的组件,默认都是单例的,也是单例的体现。
工厂模式
简单工厂模式
比如车有很多品牌:奥迪、宝马、保时捷...如果我要一辆宝马,那我得手动new,要一辆保时捷还是得new。那简单工厂模式,在这里可以定义一个创建车工厂类,传入参数拿到不同品牌车。如:
Car car = CarFactory.getCar(String brand);
抽象工厂模式
抽象工厂模式是简单工厂模式的升级版。简单工厂模式从一个工厂拿不同牌子的车,那如果某个牌子中细分有车型,颜色....那单个工厂显然不够用了
利用抽象工厂模式,可以从工厂方法A中拿到某个牌子的工厂B,再根据B拿到具体的车,如下:
BrandCarFactory brandCarFactory = CarFactory.getBrandCarFactory(String brand);
Car car = brandCarFactory.getCar(String color,String size....)
原型模式
原型模式,通过原型对象构建出和他属性一样的实例。比如说创建10只羊,每次羊都叫喜羊羊,18岁。当第一只创建后,第二只的创建属性都从第一支获取
spring的bean配置为多例时,利用到的就是原型模式。
建造者模式
建造者模式,和工厂模式有点类似。说起来有点难讲,还是看下例子:
- 执行入口:
public class Demo{
public static void main(String[] args) {
HouseDiretor dir = new HouseDiretor(new HightHouse());
House house = dir.buildHouse();
}
}
- 各个类:
//房子构造者
public abstract class HouseBuilder{
private House house = new House();
public void buildA();
public void buildB();
public void buildC();
public void buildHouse(){
return house;
}
}
//高楼
public class HightHouse extends HouseBuilder{
public void buildA(){
...
}
public void buildB(){
...
}
public void buildC(){
....
}
}
//指挥者
public class HouseDiretor{
private HouseBuilder builder;
public HouseDiretor(HouseBuilder builder){
this.builder = builder;
}
public void buildHouse(){
builder.buildA();
builder.buildB();
builder.buildC();
return builder.buildHouse();
}
}
适配器模式
适配器模式,就很好理解了。
平时大家见过的转接头就是适配器,比如你笔记本只有USB接口,但插口是HIDM,这就需要一个HIDM转USB的转换器充当连接。
类适配器模式
下面以充电器将220V转5V电压作为适配器来编写例子:
5V接口:
public interface Inter5V{
public int output5V();
}
220V实现类
public class Impl220V {
public int output220V(){
return 220;
}
}
适配器类
public class Impl5V extends Impl220V implement Inter5V{
public int output5V(){
return output220V()/24
}
}
比如现在手机要充电
public class Phone{
public void charging(Inter5V inter5V){
if(inter5V.output5V == 5){
//可以充电了
}else{
//不能充电
}
}
}
public static void main(String[] args) {
Phone phone = new Phone();
phone.charging(new Impl55V)
}
对象适配器模式
类适配器模式在于继承,这种方式有局限性。
而对象适配器模式在于聚合,没有继承关系限制。还是按上面的例子,但是某些类发生变化:
适配器类
public class Impl5V implement Inter5V{
private Impl220V impl220V;;
public Impl20V(Impl220V impl220V){
this.impl220V = impl220V;
}
public int output5V(){
return impl220V.output220V()/24
}
}
充电入口:
public static void main(String[] args) {
Phone phone = new Phone();
phone.charging(new Impl55V(new Impl220V()))
}
接口适配器模式
接口适配器模式,和上面两种不太一样。他解决是这样一个问题:接口的方法不想全部实现,只实现自己要用的即可
接口适配器往往会定义抽一个抽象类,去实现A接口的所有方法,但是方法体全为空。然后我们再去继承抽象类,选择性重写自己的方法即可。
装饰者模式
装饰者模式,在于解决银排列组合问题。就比如说牛肉面,排骨面...这些都是固定死的,理想状态是一碗面,想加啥自己加。
在Java在装饰罩的体现,有个很重要的前提,就是被装饰着和装饰者都会实现或继承相同的父类,具体参考如下:
https://blog.csdn.net/m0_47944994/article/details/127901010
装饰者A a = new 装饰者A(new 被装饰者)
装饰者B b = new 装饰者B(new 被装饰者)
代理模式
代理模式,在不改动A方法的基础上,代理类(增强类)对A方法进行前后的增强。
代理模式可以分为三种:静态代理,动态代理(JDK代理,接口代理),cglib代理
静态代理
静态代理,有个重要的前提是:代理类和被代理类都要实现同一接口,直接上例子:
同一接口:
public interface ITeateacher{
public void teach();
}
被代理类:
public class Teacher implments ITeateacher{
public void teach(){
System.out.println("教学生");
}
}
代理类:
public class TeacherProxy implments ITeateacher{
public ITeateacher teacher;
public TeacherProxy(ITeateacher teacher){
this.teacher = teacher;
}
public void teach(){
System.out.println("备课");
teacher.teacher();
System.out.println("下课");
}
}
使用:
public static void main(String[] args) {
ITeateacher teacher = new TeacherProxy(nwe Teacher());
teacher.teach()
}
好处就不说了,就是方法增强了。但缺点是实现同一接口,后面接口方法进行拓展不好维护
动态代理
动态代理也被叫JDK代理,因为代理对象是依赖JDK的API来生成的,不需要我们去创建代理类。
前提要求是目标类是要实现接口的,并且是对接口的所有方法进行增强,实例如下:
目标类接口:
public interface ITeacherDao {
public String teach(String person);
}
目标类:
public class TeacherDao implements ITeacherDao{
@Override
public String teach(String person) {
return person + "在教书";
}
}
代理工厂类,我们编写用于获取代理对象:
public class ProxyFactory {
public ProxyFactory(Object targetObj){
this.targetObj = targetObj;
}
public Object getProxyIntance(){
return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces()
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("增强前代码");
Object returnValue = method.invoke(targetObj, args);
System.out.println(returnValue);
System.out.println("增强后代码");
return returnValue;
}
});
}
}
使用:
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory(new TeacherDao());
//获取代理对象(JDK帮我们生成的)
ITeacherDao proxyIntance = (ITeacherDao) proxyFactory.getProxyIntance();
proxyIntance.teach("张三");
}
动态代理生成代理对象其实也实现了接口,和静态一样。不一样是代理对象是JDK帮我们做了而已
cglib代理
cglib代理,如果说目标类是不需要实现任何接口的,那么就用不了动态代理,但是cglib代理可以解决
注意cglib是一个框架包,需要咨询引入使用。下面直接上代码:
目标类:
public class TeacherDao{
public String teach(String person) {
return person + "在教书";
}
}
代理工厂类:
public class ProxyFactory implements MethodInterceptor {
private Object targetObj;
public ProxyFactory(Object targetObj){
this.targetObj = targetObj;
}
public Object getProxyIntance(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObj.getClass());//设置父类,cglib原理就是通过继承目标类来生成子类(代理类)
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib增强,增强前----");
Object returnValue = method.invoke(targetObj, args);
System.out.println(returnValue);
System.out.println("cglib增强,增强后----");
return returnValue;
}
}
使用
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory(new TeacherDao());
//获取代理对象(JDK帮我们生成的)
TeacherDao proxyIntance = (TeacherDao) proxyFactory.getProxyIntance();
proxyIntance.teach("张三");
}
模板模式
模板模式很简单,就是定义了一套流程所需的接口和并且子类实现。比如RedisTemplate,JdbcTemplate
Java:一篇学好设计模式的更多相关文章
- 【Todo】【读书笔记】Java多线程编程指南-设计模式篇
下了这本书<Java多线程编程指南-设计模式篇>, 还有另一本<JAVA多线程设计模式>,据说内容有重复,结合着看.
- Java 开发23种设计模式
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- java提高篇(三十)-----Iterator
迭代对于我们搞Java的来说绝对不陌生.我们常常使用JDK提供的迭代接口进行Java集合的迭代. Iterator iterator = list.iterator(); while(iterator ...
- java提高篇(十七)-----异常(二)
承接上篇博文:java提高篇-----异常(一) 五.自定义异常 Java确实给我们提供了非常多的异常,但是异常体系是不可能预见所有的希望加以报告的错误,所以Java允许我们自定义异常来表 ...
- java提高篇---Iterator
迭代对于我们搞Java的来说绝对不陌生.我们常常使用JDK提供的迭代接口进行Java集合的迭代. Iterator iterator = list.iterator(); while(iterator ...
- JAVA:23种设计模式详解(转)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- 第80节:Java中的MVC设计模式
第80节:Java中的MVC设计模式 前言 了解java中的mvc模式.复习以及回顾! 事务,设置自动连接提交关闭. setAutoCommit(false); conn.commit(); conn ...
- Java的23种设计模式<一>
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...
- Java中的模板设计模式,太实用了!
顾名思义,模板设计模式就是将许多公用的常用的代码封装成一个模板,我们只需要实现不同的业务需求的代码,然后和模板组合在一起,那么就得到完整的逻辑. 在我们的日常开发中,常用的模板模式有两种实现方式:继承 ...
- Java提高篇——单例模式
介绍 在我们日常的工作中经常需要在应用程序中保持一个唯一的实例,如:IO处理,数据库操作等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就是我们今天要 ...
随机推荐
- 阿里云Linux服务器安装Maven实战教程
下载地址 https://maven.apache.org/download.cgi 文件上传 把下载的文件上传到阿里云服务器 /usr/local/software 的目录(使用工具) window ...
- 搭建sftp服务器
sftp采用的是ssh加密隧道,安装性方面较ftp强,而且依赖的是系统自带的ssh服务,不像ftp还需要额外的进行安装 1. 创建sftp组 # groupadd sftp 创建完成之后使用ca ...
- 【PostgreSql】more than one owned sequence found
do --check seq not in sync $$ declare _r record; _i bigint; _m bigint; begin for _r in ( Select DIST ...
- jdbc连接数据库access denied for user 'root'@'localhost'(using password:YES)
navicat可以进行连接,一般原因为mysql未启用远程连接 以下为解决方案 解决方法-更新用户加密方式: MySQL [mysql]> ALTER USER 'root'@'%' IDENT ...
- Pintia 7-3 列车调度
7-3 列车调度 (25 分) 火车站的列车调度铁轨的结构如下图所示. 两端分别是一条入口(Entrance)轨道和一条出口(Exit)轨道,它们之间有N条平行的轨道.每趟列车从入口可以选择任意一条轨 ...
- Crypto入门 (五)混合编码
前言: 这次得题目从本质上说没有什么难点,是多次利用base64和16进制编码,层层解开就好,通过这题得代码编写能很好得锻炼python代码能力,一起加油,尝试着自己写写看看把. 混合编码: 题目:J ...
- 【原创】android 7.0 通知报错 java.lang.SecurityException: You need MANAGE_USERS permission to: check if specified user a managed profile outside your profile group
项目中在后台发送通知,突然某一天测出在Android 7.0上通知发送失败,那么根据提示,我们尝试加了MANAGE_USERS权限,看起来是个系统级别权限,验证后果然无效.接着在搜索后都无果,似乎大家 ...
- Node.js+Vue.js开发王者荣耀手机端官网
一.项目初始 1.工具安装和环境搭建 node.js.npm.mongodb 编辑器:VScode 2.项目初始化 项目分为三个部分,分别是移动端界面.后台管理界面和node.js开发的整体的服务端 ...
- lcd 驱动程序框架分析
在嵌入式产品中,lcd的用途可谓很大,很多产品都会用到lcd作为人机交互的接口,在linux内核中当然也有lcd的驱动,内核中都是做好了框架,用平台设备来添加和管理不同的lcd驱动程序,因为每款arm ...
- 下载Vmware 15版本的虚拟机(转载)
参考网址: https://blog.csdn.net/ITloser_cartridge/article/details/91347452 不登录VMware的下载方法: https://blog. ...