设计原则
下面我们来看它们的使用的相关场景:
单一职责原则:类的职责单一,不能将太多的职责放在一个类中,该原则是实现高内聚、低耦合的指导方针
比如:进行登录操作需要经过用户请求、参数校验、查找用户、连接数据库、操作数据库等这些操作
public class Login1 {
//登录,用户请求该方法
public String login(String username,String password){
Boolean bo = validate(username,password); //参数校验
Object user = findUser(username, password); //查找用户
if(user==null){
return "登录失败";
}
return "SUCCESS";
}
//参数校验
public Boolean validate(String username,String password){
return true;
}
//查找用户信息
public Object findUser(String username,String password){
return null;
}
//链接数据库
public Connection getConn(){
return null;
}
//操作数据库
public ResultSet query(){
return null;
}
}
根据上面的职责单一原则,我们可以将其变成:
用户请求、数据查找、数据库连接、数据库操作等
public class LoginController {
@Autowired
private LoginService loginService;
//①登录,用户请求该方法
public String login(String username,String password){
Boolean bo = validate(username,password); //参数校验
Object user = loginService.findUser(username, password); //查找用户
if(user==null){
return "登录失败";
}
return "SUCCESS";
}
//②参数校验
public Boolean validate(String username,String password){
return true;
}
}
数据查询业务
public class LoginService {
@Autowired
private LoginDao loginDao;
public Object findUser(String username, String password) {
return loginDao.query();
}
}
数据库操作:
public class LoginDao {
@Autowired
private DBUtil dbUtil;
//查询数据库
public Object query() {
return dbUtil.getConn();
}
}
数据库连接
public class DBUtil {
private Object conn;
public Object getConn() {
return conn;
}
}
这个时候,我们就实现了不同的类做不同的事了。而不是一个类做所有的事。
开闭原则:一个软件应当对扩展开发、对修改关闭。即在不修改源代码的情况下改变对象的行为
比如:我们现在需要查看报表,但是由于之前没有预留接口,导致没法进行扩展,出现需要修改原来的代码的情况:
public class PieChart {
public void display(){
System.out.println("饼状报表展示");
}
}
之后又加了一个柱状报表:
public class BarChart {
public void display(){
System.out.println("柱状报表展示");
}
}
现在想进行饼状、柱状报表的查看,代码可能是这样的:
public class ChartDisplay {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int i=sc.nextInt();
//输入1,则打印饼状报表
if(i==1){
PieChart chart = new PieChart();
chart.display();
//输入2,则打印柱状报表
}else if(i==2){
BarChart chart = new BarChart();
chart.display();
}
}
}
这个时候就不符合开闭原则了,这个时候首先想到的是给以后的更多的报表预留接口,这样方便后来的报表查看,编写一个接口,然后使用抽象类去继承,这里使用抽象类进行演示:
public abstract class AbstractChart {
abstract void display();
}
进行继承操作
柱状报表:
public class BarChart extends AbstractChart{
@Override
public void display(){
System.out.println("柱状报表展示");
}
}
饼状报表:
public class PieChart extends AbstractChart{
@Override
public void display(){
System.out.println("饼状报表展示");
}
}
进行展示
public class ChartDisplay {
private static AbstractChart abstractChart;
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
String className=sc.nextLine();
//根据输入的类名获取对应实例
setAbstractChart(className);
//调用方法
abstractChart.display();
}
/***
* 根据需要创建实例
*/
public static void setAbstractChart(String className) throws Exception {
abstractChart = (AbstractChart) Class.forName(className).newInstance();
}
}
也即首先抽象出原始接口,在原始接口的基础之后进行扩展。
里氏代换原则:在软件系统中,一个可以接收基类(父类)对象的地方必然可以接收一个子类对象。其属于开闭原则的实现
给用户发消息:
public class CommonCustomer {
private String name;
private String phone;
public CommonCustomer() {
}
public CommonCustomer(String name, String phone) {
this.name = name;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String sefInfo() {
return "给普通客户发消息,客户名字:" + name + ",客户手机号:"+phone;
}
}
vip用户:
public class VipCustomer {
private String name;
private String phone;
public VipCustomer() {
}
public VipCustomer(String name, String phone) {
this.name = name;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String sefInfo() {
return "给VIP客户发消息,客户名字:" + name + ",客户手机号:"+phone;
}
}
发消息:
public class SendMessage {
public static void main(String[] args) {
CommonCustomer commonCustomer = new CommonCustomer("王五","13670001111");
VipCustomer vipCustomer= new VipCustomer("赵六","13670001133");
send(vipCustomer);
send(commonCustomer);
}
//给VIP客户发消息
public static void send(VipCustomer vipCustomer){
System.out.println(vipCustomer.sefInfo());
}
//给普通客户发消息
public static void send(CommonCustomer commonCustomer){
System.out.println(commonCustomer.sefInfo());
}
}
从上面的代码我们可以抽象出公共的信息,同时对公共信息进行扩展,然后调用方法进行发消息
public abstract class Customer {
private String name;
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public abstract String sefInfo();
}
进行公共行为扩展:
普通用户:
public class CommonCustomer extends Customer{
@Override
public String sefInfo() {
return "给普通客户发消息,客户名字:" + super.getName() + ",客户手机号:"+super.getPhone();
}
}
vip用户
public class VipCustomer extends Customer {
@Override
public String sefInfo() {
return "给VIP客户发消息,客户名字:" + super.getName() + ",客户手机号:"+super.getPhone();
}
}
进行发送操作:
public abstract class SendMessage {
public static void main(String[] args) {
Customer commonCustomer = new CommonCustomer();
commonCustomer.setName("王五");
commonCustomer.setPhone("13670001111");
Customer vipCustomer= new VipCustomer();
vipCustomer.setName("赵六");
vipCustomer.setPhone("13670001155");
send(vipCustomer);
send(commonCustomer);
}
//给VIP客户发消息
public static void send(Customer customer){
System.out.println(customer.sefInfo());
}
}
同时在此基础上,我们可以进行对应的业务操作。
依赖倒转原则:抽象不应该依赖细节实现,细节应当依赖抽象,也即面向接口编程,用到接口的地方,通过依赖注入将接口的实现对象注入进去。
抽象接口:
public abstract class AbstractChart {
abstract void display();
}
进行继承:
public class BarChart extends AbstractChart {
@Override
public void display(){
System.out.println("柱状报表展示");
}
}
public class PieChart extends AbstractChart {
@Override
public void display(){
System.out.println("饼状报表展示");
}
}
进行展示:
public class ChartDisplay {
private AbstractChart abstractChart;
//展示报表
public void showChart(){
abstractChart.display();
}
//Setter注入
public void setAbstractChart(AbstractChart abstractChart) {
this.abstractChart = abstractChart;
}
}
接口隔离原则:不使用一个总接口,而使用多个接口进行隔离,即客户端不依赖它原本不需要调用的接口
使用一个总接口完成所有操作:
public interface DataRead {
//增删改查
void query();
void insert();
void delete();
void update();
//定时任务执行
void queryTask();
void createTask();
//报表
void reportExcel();
}
这是不符合接口隔离原则的,因此我们可以将增删查改放入一个接口,定时任务放入一个接口,报表放入一个接口
增删查改接口:
public interface CrudInterface {
//增删改查
void query();
void insert();
void delete();
void update();
}
定时任务接口:
public interface TaskInterface {
//定时任务执行
void queryTask();
void createTask();
}
报表接口:
public interface ReportInterface {
//报表
void reportExcel();
}
合成/复用原则:尽量使用对象组合,而不是使用继承来达到复用的目的
public class BookDao extends MySQLUtil {
//查询
public ResultSet query() throws Exception{
//获得数据库链接
Connection conn = super.getConn();
PreparedStatement ps = conn.prepareStatement("select * from table");
return ps.executeQuery();
}
}
如果数据源发生改变,此时就不能达到复用了,采用DBUtils,然后采用MysSQLUtils继承,进行注入,如果更换其他数据,注入即可。因此可以采用注入的放入,这样可以方便复用,工具类中,放入那个参数就使用哪个。
public class BookDao {
@Autowired
private MySQLUtil mySQLUtil;
//查询
public ResultSet query() throws Exception{
//获得数据库链接
Connection conn = mySQLUtil.getConn();
PreparedStatement ps = conn.prepareStatement("select * from table");
return ps.executeQuery();
}
}
迪米特原则:一个软件实体应当尽可以少的和其他类发生相互作用,降低耦合度
public class OrderController {
private GoodsDao goodsDao;
private OrderDao orderDao;
private LogDao logDao;
//添加订单
public void add(){
//①修改库存
goodsDao.modify();
//②增加订单
orderDao.add();
//③记录日志
logDao.recode();
}
}
修改成:
商品信息操作:
public class GoodsController {
private GoodsService goodsService;
public void modify(){
goodsService.modify();
}
}
进行订单新增:
public class OrderController {
private OrderService orderService;
//添加订单
public void add(){
}
}
logDao:
public class LogDao {
public void recode() {
System.out.println("记录日志!");
}
}
也即不同的类进行不同的操作。