设计模式之设计原则
相关设计原则图
设计原则
下面我们来看它们的使用的相关场景:
1.单一职责原则
单一职责原则:类的职责单一,不能将太多的职责放在一个类中,该原则是实现高内聚、低耦合的指导方针
比如:进行登录操作需要经过用户请求、参数校验、查找用户、连接数据库、操作数据库等这些操作
publicclassLogin1 { //登录,用户请求该方法publicStringlogin(Stringusername,Stringpassword){ Booleanbo=validate(username,password); //参数校验Objectuser=findUser(username, password); //查找用户if(user==null){ return"登录失败"; } return"SUCCESS"; } //参数校验publicBooleanvalidate(Stringusername,Stringpassword){ returntrue; } //查找用户信息publicObjectfindUser(Stringusername,Stringpassword){ returnnull; } //链接数据库publicConnectiongetConn(){ returnnull; } //操作数据库publicResultSetquery(){ returnnull; } }
根据上面的职责单一原则,我们可以将其变成:
用户请求、数据查找、数据库连接、数据库操作等
publicclassLoginController { privateLoginServiceloginService; //①登录,用户请求该方法publicStringlogin(Stringusername,Stringpassword){ Booleanbo=validate(username,password); //参数校验Objectuser=loginService.findUser(username, password); //查找用户if(user==null){ return"登录失败"; } return"SUCCESS"; } //②参数校验publicBooleanvalidate(Stringusername,Stringpassword){ returntrue; } }
数据查询业务
publicclassLoginService { privateLoginDaologinDao; publicObjectfindUser(Stringusername, Stringpassword) { returnloginDao.query(); } }
数据库操作:
publicclassLoginDao { privateDBUtildbUtil; //查询数据库publicObjectquery() { returndbUtil.getConn(); } }
数据库连接
publicclassDBUtil { privateObjectconn; publicObjectgetConn() { returnconn; } }
这个时候,我们就实现了不同的类做不同的事了。而不是一个类做所有的事。
2.开闭原则
开闭原则:一个软件应当对扩展开发、对修改关闭。即在不修改源代码的情况下改变对象的行为
比如:我们现在需要查看报表,但是由于之前没有预留接口,导致没法进行扩展,出现需要修改原来的代码的情况:
publicclassPieChart { publicvoiddisplay(){ System.out.println("饼状报表展示"); } }
之后又加了一个柱状报表:
publicclassBarChart { publicvoiddisplay(){ System.out.println("柱状报表展示"); } }
现在想进行饼状、柱状报表的查看,代码可能是这样的:
publicclassChartDisplay { publicstaticvoidmain(String[] args) { Scannersc=newScanner(System.in); inti=sc.nextInt(); //输入1,则打印饼状报表if(i==1){ PieChartchart=newPieChart(); chart.display(); //输入2,则打印柱状报表 }elseif(i==2){ BarChartchart=newBarChart(); chart.display(); } } }
这个时候就不符合开闭原则了,这个时候首先想到的是给以后的更多的报表预留接口,这样方便后来的报表查看,编写一个接口,然后使用抽象类去继承,这里使用抽象类进行演示:
publicabstractclassAbstractChart { abstractvoiddisplay(); }
进行继承操作
柱状报表:
publicclassBarChartextendsAbstractChart{ publicvoiddisplay(){ System.out.println("柱状报表展示"); } }
饼状报表:
publicclassPieChartextendsAbstractChart{ publicvoiddisplay(){ System.out.println("饼状报表展示"); } }
进行展示
publicclassChartDisplay { privatestaticAbstractChartabstractChart; publicstaticvoidmain(String[] args) throwsException { Scannersc=newScanner(System.in); StringclassName=sc.nextLine(); //根据输入的类名获取对应实例setAbstractChart(className); //调用方法abstractChart.display(); } /**** 根据需要创建实例*/publicstaticvoidsetAbstractChart(StringclassName) throwsException { abstractChart= (AbstractChart) Class.forName(className).newInstance(); } }
也即首先抽象出原始接口,在原始接口的基础之后进行扩展。
3.里氏代换原则
里氏代换原则:在软件系统中,一个可以接收基类(父类)对象的地方必然可以接收一个子类对象。其属于开闭原则的实现
给用户发消息:
publicclassCommonCustomer { privateStringname; privateStringphone; publicCommonCustomer() { } publicCommonCustomer(Stringname, Stringphone) { this.name=name; this.phone=phone; } publicStringgetName() { returnname; } publicvoidsetName(Stringname) { this.name=name; } publicStringgetPhone() { returnphone; } publicvoidsetPhone(Stringphone) { this.phone=phone; } publicStringsefInfo() { return"给普通客户发消息,客户名字:"+name+",客户手机号:"+phone; } }
vip用户:
publicclassVipCustomer { privateStringname; privateStringphone; publicVipCustomer() { } publicVipCustomer(Stringname, Stringphone) { this.name=name; this.phone=phone; } publicStringgetName() { returnname; } publicvoidsetName(Stringname) { this.name=name; } publicStringgetPhone() { returnphone; } publicvoidsetPhone(Stringphone) { this.phone=phone; } publicStringsefInfo() { return"给VIP客户发消息,客户名字:"+name+",客户手机号:"+phone; } }
发消息:
publicclassSendMessage { publicstaticvoidmain(String[] args) { CommonCustomercommonCustomer=newCommonCustomer("王五","13670001111"); VipCustomervipCustomer=newVipCustomer("赵六","13670001133"); send(vipCustomer); send(commonCustomer); } //给VIP客户发消息publicstaticvoidsend(VipCustomervipCustomer){ System.out.println(vipCustomer.sefInfo()); } //给普通客户发消息publicstaticvoidsend(CommonCustomercommonCustomer){ System.out.println(commonCustomer.sefInfo()); } }
从上面的代码我们可以抽象出公共的信息,同时对公共信息进行扩展,然后调用方法进行发消息
publicabstractclassCustomer { privateStringname; privateStringphone; publicStringgetName() { returnname; } publicvoidsetName(Stringname) { this.name=name; } publicStringgetPhone() { returnphone; } publicvoidsetPhone(Stringphone) { this.phone=phone; } publicabstractStringsefInfo(); }
进行公共行为扩展:
普通用户:
publicclassCommonCustomerextendsCustomer{ publicStringsefInfo() { return"给普通客户发消息,客户名字:"+super.getName() +",客户手机号:"+super.getPhone(); } }
vip用户
publicclassVipCustomerextendsCustomer { publicStringsefInfo() { return"给VIP客户发消息,客户名字:"+super.getName() +",客户手机号:"+super.getPhone(); } }
进行发送操作:
publicabstractclassSendMessage { publicstaticvoidmain(String[] args) { CustomercommonCustomer=newCommonCustomer(); commonCustomer.setName("王五"); commonCustomer.setPhone("13670001111"); CustomervipCustomer=newVipCustomer(); vipCustomer.setName("赵六"); vipCustomer.setPhone("13670001155"); send(vipCustomer); send(commonCustomer); } //给VIP客户发消息publicstaticvoidsend(Customercustomer){ System.out.println(customer.sefInfo()); } }
同时在此基础上,我们可以进行对应的业务操作。
4.依赖倒转原则
依赖倒转原则:抽象不应该依赖细节实现,细节应当依赖抽象,也即面向接口编程,用到接口的地方,通过依赖注入将接口的实现对象注入进去。
抽象接口:
publicabstractclassAbstractChart { abstractvoiddisplay(); }
进行继承:
publicclassBarChartextendsAbstractChart { publicvoiddisplay(){ System.out.println("柱状报表展示"); } }
publicclassPieChartextendsAbstractChart { publicvoiddisplay(){ System.out.println("饼状报表展示"); } }
进行展示:
publicclassChartDisplay { privateAbstractChartabstractChart; //展示报表publicvoidshowChart(){ abstractChart.display(); } //Setter注入publicvoidsetAbstractChart(AbstractChartabstractChart) { this.abstractChart=abstractChart; } }
5.接口隔离原则
接口隔离原则:不使用一个总接口,而使用多个接口进行隔离,即客户端不依赖它原本不需要调用的接口
使用一个总接口完成所有操作:
publicinterfaceDataRead { //增删改查voidquery(); voidinsert(); voiddelete(); voidupdate(); //定时任务执行voidqueryTask(); voidcreateTask(); //报表voidreportExcel(); }
这是不符合接口隔离原则的,因此我们可以将增删查改放入一个接口,定时任务放入一个接口,报表放入一个接口
增删查改接口:
publicinterfaceCrudInterface { //增删改查voidquery(); voidinsert(); voiddelete(); voidupdate(); }
定时任务接口:
publicinterfaceTaskInterface { //定时任务执行voidqueryTask(); voidcreateTask(); }
报表接口:
publicinterfaceReportInterface { //报表voidreportExcel(); }
6.合成/复用原则
合成/复用原则:尽量使用对象组合,而不是使用继承来达到复用的目的
publicclassBookDaoextendsMySQLUtil { //查询publicResultSetquery() throwsException{ //获得数据库链接Connectionconn=super.getConn(); PreparedStatementps=conn.prepareStatement("select * from table"); returnps.executeQuery(); } }
如果数据源发生改变,此时就不能达到复用了,采用DBUtils,然后采用MysSQLUtils继承,进行注入,如果更换其他数据,注入即可。因此可以采用注入的放入,这样可以方便复用,工具类中,放入那个参数就使用哪个。
publicclassBookDao { privateMySQLUtilmySQLUtil; //查询publicResultSetquery() throwsException{ //获得数据库链接Connectionconn=mySQLUtil.getConn(); PreparedStatementps=conn.prepareStatement("select * from table"); returnps.executeQuery(); } }
7.迪米特原则
迪米特原则:一个软件实体应当尽可以少的和其他类发生相互作用,降低耦合度
publicclassOrderController { privateGoodsDaogoodsDao; privateOrderDaoorderDao; privateLogDaologDao; //添加订单publicvoidadd(){ //①修改库存goodsDao.modify(); //②增加订单orderDao.add(); //③记录日志logDao.recode(); } }
修改成:
商品信息操作:
publicclassGoodsController { privateGoodsServicegoodsService; publicvoidmodify(){ goodsService.modify(); } }
进行订单新增:
publicclassOrderController { privateOrderServiceorderService; //添加订单publicvoidadd(){ } }
logDao:
publicclassLogDao { publicvoidrecode() { System.out.println("记录日志!"); } }
也即不同的类进行不同的操作。