一,设计模式的目的
提高代码重用性,可读性,可扩展性,可靠性,使程序具有低耦合高内聚的特征
二,七大原则
1.单一职责原则
2.接口隔离原则
3.依赖倒置原则
4.里欧替换原则
5.开闭原则
6.迪米特法则
7.合成复用原则
三,单一职责原则
1.一个类只负责一项职责
2.注意事项和细节
<1>降低类的复杂度,一个类只负责一个职责
<2>提高类的可读性,可维护性
<3>降低变更引起的风险
3.代码
<1>方案一
package 单一职责;
public class SingleResponsibility1 {
public static void main(String []args){
Vehicle vehicle=new Vehicle();
vehicle.run("汽车");
vehicle.run("飞机");
}
}
//交通工具类
//方式一
//1.方式一的run方法中违反了单一职责原则
//2.解决方案:根据交通工具运行方法不同分解成不同的类即可
class Vehicle{
public void run(String vehicle){
System.out.println(vehicle+"在路上跑");
}
}
<2>方案二
package 单一职责;
public class SingleResponseibility2 {
public static void main(String []arg){
new AirVehicle().run("飞机");
}
}
//方案二
//遵守单一职责原则
//但是代码改动大
//可以直接改动Vehicle
class RoadVehicle{
public void run(String name){
System.out.println(name+"在公路上跑");
}
}
class AirVehicle{
public void run(String name){
System.out.println(name+"在天上飞");
}
}
class WaterVehicle{
public void run(String name){
System.out.println(name+"在水中游");
}
}
<3>方案三
package 单一职责;
public class SingleResponsibility3 {
public static void main(String[]args){
}
}
//方式3
//没有对原来的类进行大的修改
//在方法上遵守了单一职责原则
//
class Vehicle2{
public void run(String name){
System.out.println(name+"在路上跑");
}
public void runAir(String name){
System.out.println(name+"在天上飞");
}
public void runWater(String name){
System.out.println(name+"在水中游");
}
}
四,接口隔离原则
1.客户端不应该依赖他不需要的接口,即一个类对另一个类的依赖应该建立在最小接口上
2.代码实例
关系:类a通过接口1依赖于类b用到接口1中的1,2,3方法,类c通过接口1依赖类d会用到接口1中的1,4,5方法
<1>没有遵循接口隔离原则的代码
package 接口隔离;
public class Segeration1 {
public static void main(String []args){
}
}
interface Interface1{
void operation1();
void operation2();
void operation3();
void operation4();
void operation5();
}
class B implements Interface1{
@Override
public void operation1() {
System.out.println("B实现了方法1");
}
@Override
public void operation2() {
System.out.println("B实现了方法2");
}
@Override
public void operation3() {
System.out.println("B实现了方法3");
}
@Override
public void operation4() {
System.out.println("B实现了方法4");
}
@Override
public void operation5() {
System.out.println("B实现了方法5");
}
}
class D implements Interface1{
@Override
public void operation1() {
System.out.println("D实现了方法1");
}
@Override
public void operation2() {
System.out.println("D实现了方法2");
}
@Override
public void operation3() {
System.out.println("D实现了方法3");
}
@Override
public void operation4() {
System.out.println("D实现了方法4");
}
@Override
public void operation5() {
System.out.println("D实现了方法5");
}
}
class A{
public void Depend1(Interface1 i){
i.operation1();
}
public void Depend2(Interface1 i){
i.operation2();
}
public void Depend3(Interface1 i){
i.operation3();
}
}
class C{
public void Depend1(Interface1 i){
i.operation1();
}
public void Depend4(Interface1 i){
i.operation4();
}
public void Depend5(Interface1 i){
i.operation5();
}
}
<2>遵循接口隔离原则的代码
package 接口隔离.改进;
public class Segeration {
}
interface Interface1{
void operation1();
}
interface Interface2{
void operation2();
void operation3();
}
interface Interface3{
void operation4();
void operation5();
}
class B implements Interface1,Interface2{
@Override
public void operation1() {
System.out.println("B实现了方法1");
}
@Override
public void operation2() {
System.out.println("B实现了方法2");
}
@Override
public void operation3() {
System.out.println("B实现了方法3");
}
}
class D implements Interface1,Interface3{
@Override
public void operation1() {
System.out.println("D实现了方法1");
}
@Override
public void operation4() {
System.out.println("D实现了方法4");
}
@Override
public void operation5() {
System.out.println("D实现了方法5");
}
}
class A{
public void Depend1(Interface1 i){
i.operation1();
}
public void Depend2(Interface2 i){
i.operation2();
}
public void Depend3(Interface2 i){
i.operation3();
}
}
class C{
public void Depend1(Interface1 i){
i.operation1();
}
public void Depend4(Interface3 i){
i.operation4();
}
public void Depend5(Interface3 i){
i.operation5();
}
}
3.分析
<1>类a通过接口1依赖于类b,接口c用过接口1依赖于类d,由于接口1对于类a和类c不是最小接口,导致类 b和类d必须去实现他们不需要的方法
<2>将接口1拆分成三个接口,接口1只有方法1,接口2包含方法2,3.接口3包含方法4,5
<3>通过以上三个接口运用接口隔离原则即可
五,依赖倒转原则
1.高层模块不应该依赖底层模块,二者都应该依赖其抽象
2.抽象不应该依赖细节,细节应该依赖抽象
3.依赖倒转的中心思想是面向接口编程
4.设计理念:相对于细节的多变性,抽象的东西更加稳定,以抽象为基础搭建的架构比细节为基础的架构更加稳定
5.使用接口和抽象类的目的是制定好规范,而不涉及任何具体的细节,把展现细节的任务交给其具体实现类
6.代码
<1>未改进
package 依赖倒转;
public class Demo {
public static void main(String []args){
new Person().get(new Email());
}
}
//完成一个Person类接受消息
//方案一
//如果我们获取的对象是微信,短息,则需要新增加类,Person类也要增加响应的方法
class Email{
public String getInfo(){
return "电子邮件";
}
}
class Person
{
public void get(Email email){
System.out.println(email.getInfo());
}
}
<2>改进后
package 依赖倒转.改进;
public class Demochange {
public static void main(String []args){
Person person=new Person();
person.get(new Email());
person.get(new Wchat());
}
}
interface Information{
String getInfor();
}
class Email implements Information{
@Override
public String getInfor() {
return "Email消息";
}
}
class Wchat implements Information{
@Override
public String getInfor() {
return "Wchat信息";
}
}
class Person{
public void get(Information information){
System.out.println(information.getInfor());
}
}
六,里氏替换
1.如果对每个类型为T1的对象O1,都有对于类型为T2的对象O2,使得定义的所有程序P在所有的对象O1替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型,也就是说,所有引用基类的地方必须能够透明的使用子类对象
2.在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类方法
3.里氏替换原则指出,继承实际上让两个类的耦合性增强了,在适当的情况下,可以通过耦合,组合,依赖来解决问题
4.代码
<1>未改进前
package 里氏替换;
public class Demo {
public static void main(String []args){
}
}
class A{
int func1(int a,int b){
return a-b;
}
}
class B extends A{
//重写了fun1方法,可能是无意识的
int fun1(int a,int b){
return a+b;
}
int fun2(int a,int b){
return fun1(a,b)+9;
}
}
*<2>改进后
package 里氏替换.改进;
import jdk.nashorn.internal.ir.BaseNode;
public class ImproveDemo {
public static void main(String []args){
}
}
class Base{
int fun1(int a,int b){
return a+b;
}
}
class A extends Base{
int fun1(int a,int b){
return a-b;
}
}
class B extends Base{
int fun1(int a,int b){
return new A().fun1(a,b);
}
int fun2(int a,int b){
return fun1(a,b)+9;
}
}
七,开闭原则
1.开闭原则是最基础最重要的原则
2.对扩展开放(针对功能提供方),对修改关闭(针对功能使用方),用抽象构建框架,用实现扩展细节
3.当软件需要变化时,尽量通过扩展软件实体的行为实现变化,而不是通过修改已有的代码实现变化
4.编程中遵循的其他原则以及使用设计模式的目的就是遵循开闭原则
5.代码
<1>完成绘制矩形和圆形的功能
package 开闭原则;
public class OcP {
public static void main(String []args){
}
}
class GraphicEditor{
public void drawShape(Shape s){
if(s.m_type==1){
drawRectangle();
}else if(s.m_type==2){
drawCircle();
}
}
public void drawRectangle(){
System.out.println("绘制矩形");
}
public void drawCircle(){
System.out.println("绘制圆形");
}
}
class Shape{
int m_type;
}
class Rectangle extends Shape{
Rectangle(){
super.m_type=1;
}
}
class Circle extends Shape{
Circle(){
super.m_type=2;
}
}
<2>在1中代码的基础上添加绘制三角形的功能
package 开闭原则;
public class Ocp2 {
public static void main(String []args){
System.out.println();
}
}
class GraphicEditor1{
public void drawShape(Shape s){
if(s.m_type==1){
drawRectangle();
}else if(s.m_type==2){
drawCircle();
}else if(s.m_type==3){
drawTriangle();
}
}
public void drawRectangle(){
System.out.println("绘制矩形");
}
public void drawCircle(){
System.out.println("绘制圆形");
}
public void drawTriangle(){System.out.print("绘制三角形");}
}
class Shape1{
int m_type;
}
class Rectangle1 extends Shape1{
Rectangle1(){
super.m_type=1;
}
}
class Circle1 extends Shape1{
Circle1(){
super.m_type=2;
}
}
class Triangle extends Shape1{
Triangle(){super.m_type=3;}
}
从代码1到代码2,添加绘制三角形功能时,违背了开闭原则,因为对使用方GraphicEditor进行了更改
<3>对代码进行完善
定义抽象类Shape,在其中定义draw方法,让其他图形继承该抽象类,并实现自己的draw方法,在使用方会制图形时直接调用draw方法即可
package 开闭原则.improve;
public class OCP {
public static void main(String []args) {
}
}
class GraphicEditor{
public static void drawShape(Shape shape){
shape.draw();
}
}
abstract class Shape{
public abstract void draw();
}
class Rectangle extends Shape{
@Override
public void draw() {
System.out.println("绘制矩形");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("绘制三角型");
}
}
class Circle extends Shape{
@Override
public void draw() {
System.out.println("绘制圆形");
}
}
class OtherShape extends Shape{
@Override
public void draw() {
System.out.println("绘制其他图形");
}
}
八,迪米特法则
1.一个对象应该对其他对象保持最少的了解
2.类与类之间的关系越密切,耦合度越大
3.又称最少知道原则,即一个类对自己依赖的知道的越少越好
4.代码
打印学校员工和学院员工
<1>未改进
package 迪米特法则;
import javax.swing.event.ListDataEvent;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String []args){
SchoolManager schoolManager=new SchoolManager();
schoolManager.printAllEmployee(new CollageManager());
}
}
//学校员工
class Employee{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
//学院员工
class CollageEmployee{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
class CollageManager{
//返回学院的所有员工
public List<CollageEmployee> getAllCollageEmployee(){
List<CollageEmployee>list=new ArrayList<>();
for(int i=0;i<5;i++){
CollageEmployee collageEmployee=new CollageEmployee();
collageEmployee.setId("学院员工编号"+i);
list.add(collageEmployee);
}
return list;
}
}
class SchoolManager{
public List<Employee> getAllEmployee(){
List<Employee> list=new ArrayList<>();
for(int i=0;i<5;i++){
Employee employee=new Employee();
employee.setId("学校员工编号"+i);
list.add(employee);
}
return list;
}
public void printAllEmployee(CollageManager collageManager){
List<CollageEmployee> list1=collageManager.getAllCollageEmployee();
for(CollageEmployee i:list1){
System.out.println(i.getId());
}
List<Employee> list2=this.getAllEmployee();
System.out.println("==================================================");
for(Employee i:list2){
System.out.println(i.getId());
}
}
}
SchoolManeger与CollageEmployee在printAllEmployee方法种建立了依赖关系,实际上这种关系是没必要的,将输出学院员工的代码封装到CoolageManeger中即可
<2>改进后的代码
package 迪米特法则.Improve;
import javax.swing.event.ListDataEvent;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String []args){
SchoolManager schoolManager=new SchoolManager();
schoolManager.printAllEmployee(new CollageManager());
}
}
//学校员工
class Employee{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
//学院员工
class CollageEmployee{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
class CollageManager{
//返回学院的所有员工
public List<CollageEmployee> getAllCollageEmployee(){
List<CollageEmployee>list=new ArrayList<>();
for(int i=0;i<5;i++){
CollageEmployee collageEmployee=new CollageEmployee();
collageEmployee.setId("学院员工编号"+i);
list.add(collageEmployee);
}
return list;
}
public void printAllCollageEmployee(){
List<CollageEmployee> list1=this.getAllCollageEmployee();
for(CollageEmployee i:list1){
System.out.println(i.getId());
}
}
}
class SchoolManager{
public List<Employee> getAllEmployee(){
List<Employee> list=new ArrayList<>();
for(int i=0;i<5;i++){
Employee employee=new Employee();
employee.setId("学校员工编号"+i);
list.add(employee);
}
return list;
}
public void printAllEmployee(CollageManager collageManager){
collageManager.printAllCollageEmployee();
List<Employee> list2=this.getAllEmployee();
System.out.println("==================================================");
for(Employee i:list2){
System.out.println(i.getId());
}
}
}
九,合成复用法则
1.尽量使用合成聚合的方式,而不是使用继承