这是我参与更文挑战的第1天,活动详情查看:更文挑战
java语言的特性是封装、多态、继承,设计模式就是在此特性上诞生各种业务场景的解决方案
使用设计模式的目的是为了 让我们的软件有更好的
- 代码重用性(相同的代码不用多次编写)
- 可读性(编码规范性,便于其他程序员的阅读和理解)
- 可扩展性(方便增加新的功能)
- 可靠性(当我们增加新的功能后 对原来功能没有影响)
- 使程序呈现 高内聚,低耦合
设计模式在软件开发中的应用: 面向对象(oop)=>功能模块设计(设计模式+算法)=>框架(多种设计模式)=>架构(服务集群)
设计模式七大原则
- 单一职责原则
- 接口隔离原则
- 依赖倒转原则
- 里氏替换原则
- 开闭原则
- 迪米特原则
- 合成复用原则
单一职责原则:
一个类应该只负责一项职责,但并不是只有一个方法
接口隔离原则:
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上
如:实际生产中 接口之间依赖关系错综复杂 就会产生循环依赖问题
依赖倒转原则
- 高层模块不应该依赖底层模块,二者都应该依赖抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 依赖倒转的中心思想是面向接口编程
在java中抽象指的是 接口或抽象类,细节指的是具体的实现类
示例业务需求
给手机实现接收微信 接收邮件功能
反面案例:
定义邮件功能
class Email0{
public String getInfo(){
return "Email0: hello!";
}
}
复制代码
定义微信功能
class Weixin0{
public String getInfo(){
return "Weixin0: hello!";
}
}
复制代码
定义手机 实现接收邮件 接收微信的功能
class Phone{
public void recieve(Email0 email0){
System.out.println(email0.getInfo());
}
public void recieveWeixin(Weixin0 weixin0){
System.out.println(weixin0.getInfo());
}
}
复制代码
定义客户端使用手机
public class DependenceInversion {
public static void main(String[] args) {
new Phone().recieve(new Email0());
new Phone().recieveWeixin(new Weixin0());
}
}
复制代码
以上这种写法也可以实现功能 但是代码看起来比较臃肿而且不容易维护。
假如现在增加 让手机可以接收短信的功能,则需要:
- 定义好短信功能
- 手机类实现接收短信功能
- 客户端使用手机调用接收短信方法
在第二步则违背了 依赖倒转原则 高层部分直接依赖了底层模块,细节依赖细节,复杂的业务逻辑没有抽象层支撑;
优化:
定义抽象层”接收信息”
各部分功能实现抽象层 编写对应的功能逻辑
手机功能依赖抽象层
客户端根据自己需求 定义手机实现对应功能
优化后代码
定义接口
interface Ireceiver{
String getInfo();
}
复制代码
定义邮件功能 实现接口
class Email implements Ireceiver{
@Override
public String getInfo() {
return "邮件服务:hello word";
}
}
复制代码
定义微信功能 实现接口
class Weixin implements Ireceiver{
@Override
public String getInfo() {
return "微信服务:hello weixin";
}
}
复制代码
定义手机 依赖于抽象层
class Person{
public void receive(Ireceiver ireceiver){
System.out.println(ireceiver.getInfo());
}
}
复制代码
定义客户端使用手机不同功能
public class DependenceInversion1 {
public static void main(String[] args) {
Person person=new Person();
person.receive(new Email());
person.receive(new Weixin());
}
}
复制代码
依赖关系传递的三种方式:
示例业务需求:
存在播放器 player 需要使用接口类ITV 中的play方法
接口传递
ITV接口
interface ITV{
public void play();
}
复制代码
player 接口
interface IPlayer{
public void open(ITV itv);
}
复制代码
player 类
class Player implements IPlayer{
@Override
public void open(ITV itv) {
itv.play();
}
}
复制代码
构造方法传递
ITV接口
interface ITV2{
public void play();
}
复制代码
player 接口
interface IPlayer2{
public void open();
}
复制代码
player 类
class Player2 implements IPlayer2{
public ITV2 tv;
public Player2(ITV2 tv){
this.tv=tv;
}
@Override
public void open() {
this.tv.play();
}
}
复制代码
setter方式传递
ITV 接口
interface ITV3{
void play();
}
复制代码
player 接口
interface Player3{
void open();
}
复制代码
player 类
class Player3 implements IPlayer3{
private ITV3 tv;
public void setTv(ITV3 tv) {
this.tv = tv;
}
@Override
public void open() {
this.tv.play();
}
}
复制代码
依赖倒转细节
- 低层模块尽量都要有抽象类或者接口,或者两者都有,程序稳定性更好。
- 变量的声明类型尽量是抽象类或者接口,这样我们的变量引用和实际对象间就存在一个缓冲层,利于程序的扩展和优化。
- 继承时遵循里氏替换原则。
时间原因暂时先写到这 里氏替换原则详见下一篇
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END