标签:void inxi 好的 inf ntc enter win 基础上 框架
(1)指的是在开发的过程中尽量的去扩展代码,而不是去修改原来的代码,以免影响到之前的逻辑。
(2)强调的是用抽象构建框架,用实现扩展细节。
(3)可以提高软件系统的可复用性及可维护性
(2)例:原有课程类,闲杂要对课程进行打折,应该怎么处理呢?
原有课程类:
package test1; /** * author:songyan * date: 2019/10/6 **/ public interface Course { public String getId(); public String getName(); public double getPrice(); }
package test1; /** * author:songyan * date: 2019/10/6 **/ public class JavaCourse implements Course { private String id; private String name; private double price; @Override public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public JavaCourse(String id, String name, double price) { this.id = id; this.name = name; this.price = price; } }
新增打折课程类
package test1; /** * author:songyan * date: 2019/10/6 **/ public class JavaDiscountCourse extends JavaCourse{ public JavaDiscountCourse(String id, String name, double price) { super(id, name, price); } public double getOriginPrice() { return super.getPrice(); } public double getPrice() { return super.getPrice()*0.8; } }
在不修改原来的逻辑的基础上作出对应的修改
测试类:
package test1; /** * author:songyan * date: 2019/10/6 **/ public class Test { public static void main(String[] args) { JavaDiscountCourse cource = new JavaDiscountCourse("001","java",100.0); System.out.println(cource.getPrice()); System.out.println(cource.getOriginPrice()); } }
(1)要求对抽象进行编程,不要对实现进行编程。
(2)降低了客户与实现模块间的耦合。
(3)例:原有转换工具类可以转换word,pdf两种类型的文件,现在该工具类需要扩展使其在原来的基础上还能转换excel文件
如果是按照依赖实现编程:
package test2; /** * des: office文档转pdf类 * author:songyan * date: 2019/10/6 **/ public class Trans { public void transWord(){ System.out.println("转换"); } public void transPDF(){ System.out.println("pdf转换"); } }
客户端:
package test2; /** * author:songyan * date: 2019/10/6 **/ public class Client { public static void main(String[] args) { Trans trans = new Trans(); trans.transWord(); trans.transPDF(); } }
使用这种方式的弊端就在于,如果说要扩展转换工具类的工具类的功能,就需要去修改之前的代码,显然这种做法是非常不安全的,有可能就会影响之前代码。
更好的做法是:
package test2; /** * author:songyan * date: 2019/10/6 **/ public class TransUtil { public void trans(OfficeDocument document){ document.trans(); } }
package test2; /** * author:songyan * date: 2019/10/6 **/ public class WordDocument implements OfficeDocument { @Override public void trans() { System.out.println("word文档转换"); } }
package test2; /** * author:songyan * date: 2019/10/6 **/ public class PDFDocuemnt implements OfficeDocument{ @Override public void trans() { System.out.println("pdf转换"); } }
package test2; /** * author:songyan * date: 2019/10/6 **/ public class Test { public static void main(String[] args) { TransUtil trnas = new TransUtil(); trnas.trans(new WordDocument()); trnas.trans(new PDFDocuemnt()); } }
在转换工具类中是针对处理对象的接口进行处理的,在想要扩展功能的时候只需要添加一个实现类即可,例如:
package test2; /** * author:songyan * date: 2019/10/6 **/ public class ExcelDocument implements OfficeDocument{ @Override public void trans() { System.out.println("excel转换"); } }
package test2; /** * author:songyan * date: 2019/10/6 **/ public class Test { public static void main(String[] args) { TransUtil trnas = new TransUtil(); trnas.trans(new WordDocument()); trnas.trans(new PDFDocuemnt()); trnas.trans(new ExcelDocument()); } }
使用这种方法只需要扩展之前的代码,而不需要修改之前的代码,其实也就是上面说开闭原则。
这个例子其实就是“依赖注入”,那么依赖注入的方式又包括构造器注入,setter方法注入,下面简介一下这两种方式
1)构造器注入
package test2.generator; import test2.OfficeDocument; /** * author:songyan * date: 2019/10/6 **/ public class TransUtil { private OfficeDocument officeDocument; public TransUtil(OfficeDocument officeDocument) { this.officeDocument = officeDocument; } public void trans() { officeDocument.trans(); } }
package test2.generator; import test2.WordDocument; /** * author:songyan * date: 2019/10/6 **/ public class Test { public static void main(String[] args) { TransUtil transUtil = new TransUtil(new WordDocument()); transUtil.trans(); } }
2)setter方式注入
package test2.setter; import test2.OfficeDocument; /** * author:songyan * date: 2019/10/6 **/ public class TransUtil { private OfficeDocument officeDocument; public void setOfficeDocument(OfficeDocument officeDocument) { this.officeDocument = officeDocument; } public void trans(){ officeDocument.trans(); } }
package test2.setter; import test2.WordDocument; /** * author:songyan * date: 2019/10/6 **/ public class Test { public static void main(String[] args) { TransUtil transUtil= new TransUtil(); transUtil.setOfficeDocument(new WordDocument()); transUtil.trans(); } }
以抽象为基准比以细节为基准搭建起来的框架要稳健的多,因此,大家在拿到需求之后要面向抽象接口来编程,先顶层在底层来设计代码结构。
(1)如果有多个职能,则其中一个职能发生改变之后,就需要修改这个类的功能,就有可能影响到另一个职能。所以我们有必要对他们进行一定程度的拆分。
(2)降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险
(3)例:有一个对nginx操作的工具类如下:
package test3; /** * Nginx工具类 * author:songyan * date: 2019/10/6 **/ public class NginxUtil { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void start(){ System.out.println("启动nginx"); } }
里面有设计nginx基本信息的方法,也有启动nginx的方法,比如说,nginx的启动方法发生了改变,这个时候就需要修改nginxUtil类,那再修改的过程中就有可能对他的其他方法产生影响,因此我们可以对他进行以下划分,将他隔离开:
package test3; /** * author:songyan * date: 2019/10/6 **/ public class NginxInfo { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
package test3; /** * author:songyan * date: 2019/10/6 **/ public class NginxOperator { public void start(){ System.out.println("nginx启动"); } }
接口与此类似。。
方法不符合单一职责而原则的例子:
public void modefied(String name,String fav){ System.out.println("修改名字"); System.out.println("修改爱好"); }
方法符合单一职责而原则的例子:
public void modefiedName(String name){ System.out.println("修改姓名"); } public void modefiedFav(String fav){ System.out.println("修改爱好"); }
其实这种方式乍一看可能感觉不到这样写的好处在哪里,我突然想到我最近的一个任务,是修改之前的同事写的一个系统,里面大多数的逻辑代码都是摞在一起的,一个方法中有几百行代码,做什么的都有,可能有的时候只需要改其中的一个点,但是可能就会影响到其他部分的代码,还有一个缺点就是,里面的代码错综复杂,可能的要找到你想改的地方都很难。
总结一下就是,在写代码的过程中如果尽量的保持单一指责原则就会,提高类的可读性,提高系统的可维护性,降低变更引起的风险。
(1)一个类对一个类的接口应该建立在最小的接口之上。
(2)尽力单一的接口,而不要建立单一臃肿的接口
(3)尽量的细化接口,接口中的方法尽量少(不是越少越好,要适度)
(4)例:前几天总结的office文档转pdf的方式,其中openoffice,aspose是支持windows,linux两种系统的,但是jacob只支持windows系统,下面的代码就会存在一定的问题。
在下面的代码中,将windows转换的方式,Linux转换的方式放在了一个接口中:
package test4; /** * author:songyan * date: 2019/10/6 **/ public interface Itrans { void windowsTrans(); void linuxTrans(); }
在openoffice,aspose两种方式中,是没有问题的,见下:
package test4; /** * author:songyan * date: 2019/10/6 **/ public class AsposeTrans implements Itrans{ @Override public void windowsTrans() { System.out.println("Aspose在windows的转换"); } @Override public void linuxTrans() { System.out.println("Aspose在linux的转换"); } }
package test4; /** * author:songyan * date: 2019/10/6 **/ public class OpenofficeTrans implements Itrans{ @Override public void windowsTrans() { System.out.println("oppenoffice在windows的转换"); } @Override public void linuxTrans() { System.out.println("oppenoffice在linux的转换"); } }
但是,你会发现在jacob中,他是不支持在Linux的转换的,但是实现这个接口的话必须重写这个接口。。
package test4; /** * author:songyan * date: 2019/10/6 **/ public class JacobTrans implements Itrans{ @Override public void windowsTrans() { System.out.println("Jacob在windows的转换"); } @Override public void linuxTrans() { } }
针对上面的情况可以做以下完善,将接口中的方法拆分到两个接口中:
package test4; /** * author:songyan * date: 2019/10/6 **/ public interface IWindowsTrans { void windowsTrans(); }
package test4; /** * author:songyan * date: 2019/10/6 **/ public interface ILinuxTrans { void linuxTrans(); }
对两种系统都支持的方式可以去实现两种接口
package test4; /** * author:songyan * date: 2019/10/6 **/ public class AsposeTrans implements IWindowsTrans,ILinuxTrans{ @Override public void windowsTrans() { System.out.println("Aspose在windows的转换"); } @Override public void linuxTrans() { System.out.println("Aspose在linux的转换"); } }
对只支持一种系统的方式只需要实现一种接口
package test4; /** * author:songyan * date: 2019/10/6 **/ public class JacobTrans implements IWindowsTrans{ @Override public void windowsTrans() { System.out.println("Jacob在windows的转换"); } }
标签:void inxi 好的 inf ntc enter win 基础上 框架
原文地址:https://www.cnblogs.com/excellencesy/p/11627841.html