设计模式六大原则

一、开闭原则

定义:一个软件模块如类、模块和函数应该对扩展开放,对修改关闭
开闭原则强调了用抽象构建框架、用实现扩展细节。通常为了满足开闭原则,我们应该尽可能的面向抽象编程。
优点:提高软件系统的可复用性及可维护性。
具体例子:现在我们有一个课程接口,它有很多具体课程的实现类,我们可以通过具体的实现类来获取具体课程价格。

public interface Course {
	int getPrice();
	String getBookName();
}

实现类

public class JavaCourse implements Course{
	
	private int mPrice;
	private String mBookName;
	
	public JavaCourse() {};
	
	public JavaCourse(int price,String bookName) {
		mPrice=price;
		mBookName=bookName;
	}

	@Override
	public int getPrice() {
		// TODO Auto-generated method stub
		return mPrice;
	}

	@Override
	public String getBookName() {
		// TODO Auto-generated method stub
		return mBookName;
	}
}

很简单,调用JavaCourse 对象的getPrice方法我们就可以获得java课的价格,现在有一个需求:元旦快到了,我们的java课打6折,我们怎么写?
1、给Course接口增加一个用于返回打折后价格的方法吗(discountPrice)?,这显然违背了对修改封闭 ,接口应该是稳定的,最好不要修改它,因为一旦修改了接口,所有的实现类都要修改。
2、直接修改JavaCourse中的getPrice方法或者给JavaCourse增加一个discountPrice方法?如果增加一个discountPrice方法那这个类就有两个获取价格的方法了,而且下次打4折、打7折是不是都要对类进行修改。这也不符合开闭原则。
3、定义继承至JavaCourse专门用来处理打折的类:

public class JavaDiscountCourse extends JavaCourse{

	public JavaDiscountCourse(int price,String bookName) {
		super(price,bookName);
	}
	public int getDiscountPrice() {
		return (int) (getPrice()*0.6);
	}
}

这样我们就不用修改原有的类了,正如对开闭原则的定义对扩展开放,对修改关闭。通过继承现有类来扩展功能而不是修改原有类。开闭原则是面向对象编程最基础的设计原则,它指导我们如何建立一个稳定灵活的系统。

二、依赖倒置原则

定义:高层模块不应该依赖底层模块,两者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。
依赖可以理解为一种需要,A类需要用到B类,那么A就依赖B类。通常高层模块就是调用端,而底层模块就是被调用端的具体实现,高层模块和底层模块的这种定义是相对的。如果高层模块和底层模块之间的这种依赖通过具体实现发生,他们就会高度耦合。而依赖倒置原则指导我们类与类之间不应该直接依赖细节(具体的实现类),而是依赖抽象。所谓的抽象可以是接口,也可以是抽象类。
举个例子:现在我们有一个DaoService类它持有一个OracleDao对象,通过它可以操作Oracle数据库。那么DaoService就是高层模块,OracleDao就是底层模块。

public class OracleDao {
		public void select() {
			System.out.println("查询Oracle数据库");
		}
}

public class DaoService {
	private OracleDao dao;

	//注入
	public void setDao(OracleDao dao) {
		this.dao = dao;
	}
	
	public void work() {
		dao.select();
	}
}

可以看到这里依赖关系是通过细节发生的,OracleDao是具体的实现类。当我们调用DaoService。

public class Test {

	public static void main(String[] args) {
		DaoService serviec=new DaoService();
		serviec.setDao(new OracleDao());
		serviec.work();
	}

}

如果现在因为某些原因,我们需要从MySQL数据库查询数据,我们就需要修改DaoService类。

public class DaoService {
	private MySQLDao dao;

	//注入
	public void setDao(MySQLDao dao) {
		this.dao = dao;
	}
	
	public void work() {
		dao.select();
	}
}

以后操作其他数据库是不是还是需要修改DaoService类?依赖倒置的好处这时候就体现出来,再来回顾下定义:高层模块不应该依赖底层模块,两者都应该依赖其抽象。
因此我们创建一个接口,让所有的具体Dao类实现它。

//抽象
public interface Dao {
	void select();
}

//实现
public class OracleDao implements Dao{
	@Override
	public void select() {
		System.out.println("查询Oracle数据库");
	}
}

public class DaoService {
	//依赖关系通过抽象发生
	private Dao dao;

	//注入
	public void setDao(Dao dao) {
		this.dao = dao;
	}
	
	public void work() {
		dao.select();
	}
}

现在如果在替换数据库我们就不用再修改DaoService类,只需要创建一个新的类实现Dao接口。

public static void main(String[] args) {
		DaoService serviec=new DaoService();
		serviec.setDao(new OracleDao());
		serviec.work();
		
		serviec.setDao(new MySQLDao());
		serviec.work();
	}

三、接口隔离原则

定义:用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。
补充:

  • 一个类对一个类的依赖应该建立在最小的接口上。
  • 建立单一的接口,不要建立庞大臃肿的接口。
  • 尽可能细化接口,接口中的饿方法尽量少。
  • 注意适度原则,一定要适度。

优点:符合高内聚低耦合的设计思想,使类可读性更好、更易维护和扩展。
遵循接口隔离原则一定要把握好一个度,接口中方法少固然使得程序更加灵活,但同样会导致接口过多,增加系统的复杂性。
下面看一个例子:

//接口
public interface Animal {
	void eat();
	void run();
	void fly();
	void swim();
}
//实现类
public class Fish implements Animal{

	@Override
	public void eat() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void swim() {
		// TODO Auto-generated method stub
		
	}

}

定义了一个动物接口,然后创建了一个鱼实现这个接口。这个接口就不符合接口隔离原则,建立单一的接口,不要建立庞大臃肿的接口。这个接口比较大,它的实现类鱼其实能用到的只有eat()和swim(),鱼是不会run和fly的,即使我们实现了也没有。因此我们应该将接口细化。

public interface Animal {
	void eat();
}

public interface IFlyable {
	void fly();
}

public interface ISwim {
	void swim();
}

public interface IRunable {
	void run();
}

实现类

public class Fish implements Animal,ISwim{

	@Override
	public void swim() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void eat() {
		// TODO Auto-generated method stub
		
	}

}

对接口的适当拆分可以增加程序的灵活性。

四、迪米特法则

定义:一个对象应该对其他对象保持最少的了解。又叫最少知道原则。

优点:降低类与类之间的耦合。

迪米特法则强调了两点:

  • 在设计类时,每个类都应该降低成员的访问权限,不需要让别的类知道的方法和属性就不要公开。
  • 应该和朋友说话,不和陌生人说话。

第一点很好理解,对类中信息适当的隐藏有利于复用,只给依赖者提供简单的使用方法,具体方法里面怎么做的,依赖者不关心,这样可以降低类与类之间的耦合,类之间的耦合越低,越有利于复用。一个处于弱耦合的类被修改,不会对关系的类造成波及。

第二点怎么理解呢?迪米特法则告诉我们应该和直接朋友说话,不和陌生人说话,哪些是朋友呢?成员变量、方法的参数、方法返回值中的类都是直接朋友,而出现在方法体内部的局部变量不属于朋友。
举例子:
公司的boss有一天忽然找到人事经理,希望它帮忙统计下公司有多少员工。

//boss类
public class Boss {
    public void numberOfEmployees(PersonnelManager personnelManager){
       
        List<Employee> employeeList=new ArrayList<>();
        employeeList.add(new Employee("张三"));
        employeeList.add(new Employee("李四"));
        employeeList.add(new Employee("小王"));

        int num=personnelManager.numberOfEmployees(employeeList);
    }
}
//部门经理
public class PersonnelManager {
    public int numberOfEmployees(List<Employee> list){
        int num=(list==null?0:list.size());
        System.out.println("公司总共有:"+num+"人");
        return num;
    }
}

调用:

  public static void main(String[] args) {
        Boss boss=new Boss();
        boss.numberOfEmployees(new PersonnelManager());
    }

重点看下Boss这个类,它的朋友是PersonnelManager 类,而方法体中的Employee不属于它的朋友,因此Boss不应该和它交流,这就是和直接朋友说话,不和陌生人说话
修改后如下:

public class Boss {
    public void numberOfEmployees(PersonnelManager personnelManager){
        int num=personnelManager.numberOfEmployees();
    }
}

//部门经理
public class PersonnelManager {
    public int numberOfEmployees(){
        List<Employee> employeeList=new ArrayList<>();
        employeeList.add(new Employee("张三"));
        employeeList.add(new Employee("李四"));
        employeeList.add(new Employee("小王"));
        int num=employeeList.size();
        System.out.println("公司总共有:"+num+"人");
        return num;
    }
}

未完待续~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值