编写软件过程中,程序员面临着来自耦合性、内聚性、可维护性、可扩展性、重用性、灵活性等多方面的挑战。而设计模式就是为了让软件具有更好的:
一个类只负责一个职责。如果一个类包含两个职责,如职责A和职责B,则修改职责A时,有可能会导致职责B的执行出现错误。此时应该把该类细分,即把职责A和B分到两个不同的类。
package com.zipeng.principle.singleresponsibility;
/**
* @author: zipeng Li
* 2021/4/16 21:00
*/
public class SingleResponsibility01 {
public static void main(String[] args) {
Vehicle vehicle = new Vehicle();
vehicle.run("汽车");
vehicle.run("摩托车");
vehicle.run("飞机");
}
}
class Vehicle{
public void run(String name){
System.out.println(name + " 在公路上跑");
}
}
汽车 在公路上跑
摩托车 在公路上跑
飞机 在公路上跑
package com.zipeng.principle.singleresponsibility;
/**
* @author: zipeng Li
* 2021/4/16 21:19
*/
public class SingleResponsibility02 {
public static void main(String[] args) {
RoleVehicle roleVehicle = new RoleVehicle();
roleVehicle.run("汽车");
AirVehicle airVehicle = new AirVehicle();
airVehicle.run("飞机");
}
}
class RoleVehicle{
public void run(String name){
System.out.println(name + " 在公路上跑");
}
}
class AirVehicle{
public void run(String name){
System.out.println(name + " 在天空上飞");
}
}
汽车 在公路上跑
飞机 在天空上飞
package com.zipeng.principle.singleresponsibility;
/**
* @author: zipeng Li
* 2021/4/16 21:22
*/
public class SingleResponsibility03 {
public static void main(String[] args) {
Vehicle03 vehicle03 = new Vehicle03();
vehicle03.runRole("汽车");
vehicle03.runAir("飞机");
}
}
class Vehicle03{
public void runRole(String name){
System.out.println(name + " 在公路上跑");
}
public void runAir(String name){
System.out.println(name + " 在天空上飞");
}
}
汽车 在公路上跑
飞机 在天空上飞
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小接口之上
。
package com.zipeng.principle.interfacesegregation;
/**
* @author: zipeng Li
* 2021/4/16 22:39
*/
public class InterfaceSegregation01 {
public static void main(String[] args) {
Interface1 interface1 = new B();
Interface1 interface2 = new D();
A a = new A();
C c = new C();
a.oper01(interface1);
a.oper02(interface1);
a.oper03(interface1);
c.oper01(interface2);
c.oper04(interface2);
c.oper05(interface2);
}
}
interface Interface1 {
void oper01();
void oper02();
void oper03();
void oper04();
void oper05();
}
class B implements Interface1 {
@Override
public void oper01() {
System.out.println("B 实现了 oper01");
}
@Override
public void oper02() {
System.out.println("B 实现了 oper02");
}
@Override
public void oper03() {
System.out.println("B 实现了 oper03");
}
@Override
public void oper04() {
System.out.println("B 实现了 oper04");
}
@Override
public void oper05() {
System.out.println("B 实现了 oper05");
}
}
class D implements Interface1 {
@Override
public void oper01() {
System.out.println("D 实现了 oper01");
}
@Override
public void oper02() {
System.out.println("D 实现了 oper02");
}
@Override
public void oper03() {
System.out.println("D 实现了 oper03");
}
@Override
public void oper04() {
System.out.println("D 实现了 oper04");
}
@Override
public void oper05() {
System.out.println("D 实现了 oper05");
}
}
class A {
public void oper01(Interface1 inter) {
inter.oper01();
}
public void oper02(Interface1 inter) {
inter.oper02();
}
public void oper03(Interface1 inter) {
inter.oper03();
}
}
class C {
public void oper01(Interface1 inter) {
inter.oper01();
}
public void oper04(Interface1 inter) {
inter.oper04();
}
public void oper05(Interface1 inter) {
inter.oper05();
}
}
B 实现了 oper01
B 实现了 oper02
B 实现了 oper03
D 实现了 oper01
D 实现了 oper04
D 实现了 oper05
package com.zipeng.principle.interfacesegregation;
/**
* @author: zipeng Li
* 2021/4/18 16:40
*/
public class InterfaceSegregation02 {
public static void main(String[] args) {
AA aa = new AA();
CC cc = new CC();
aa.oper01(new BB());
aa.oper02(new BB());
aa.oper03(new BB());
cc.oper01(new DD());
cc.oper04(new DD());
cc.oper05(new DD());
}
}
interface Interface01 {
void oper01();
}
interface Interface02{
void oper02();
void oper03();
}
interface Interface03{
void oper04();
void oper05();
}
class BB implements Interface01, Interface02 {
@Override
public void oper01() {
System.out.println("B 实现了 oper01");
}
@Override
public void oper02() {
System.out.println("B 实现了 oper02");
}
@Override
public void oper03() {
System.out.println("B 实现了 oper03");
}
}
class DD implements Interface01, Interface03 {
@Override
public void oper01() {
System.out.println("D 实现了 oper01");
}
@Override
public void oper04() {
System.out.println("D 实现了 oper04");
}
@Override
public void oper05() {
System.out.println("D 实现了 oper05");
}
}
class AA {
public void oper01(Interface01 inter) {
inter.oper01();
}
public void oper02(Interface02 inter) {
inter.oper02();
}
public void oper03(Interface02 inter) {
inter.oper03();
}
}
class CC {
public void oper01(Interface01 inter) {
inter.oper01();
}
public void oper04(Interface03 inter) {
inter.oper04();
}
public void oper05(Interface03 inter) {
inter.oper05();
}
}
B 实现了 oper01
B 实现了 oper02
B 实现了 oper03
D 实现了 oper01
D 实现了 oper04
D 实现了 oper05
抽象
(接口 或 抽象类)面向接口编程
设计理念
:抽象比细节更具稳定性,以抽象为基础的架构比以细节为基础的架构更能应对变化。package com.zipeng.principle.dependenceinversionprinciple;
/**
* @author: zipeng Li
* 2021/4/18 18:13
*/
public class DependenceInversionPrinciple {
public static void main(String[] args) {
Person person = new Person();
person.receiveMsg(new EMail());
}
}
class Person{
public void receiveMsg(EMail eMail){
eMail.getMsg();
}
}
class EMail{
public void getMsg(){
System.out.println("接收到e-mail的消息");
}
}
接收到e-mail的消息
package com.zipeng.principle.dependenceinversionprinciple;
/**
* @author: zipeng Li
* 2021/4/18 18:13
*/
public class DependenceInversionPrinciple {
public static void main(String[] args) {
Person person = new Person();
person.receiveMsg(new EMail());
person.receiveMsg(new WeiXin());
}
}
class Person{
public void receiveMsg(IReceive receive){
receive.getMsg();
}
}
interface IReceive{
void getMsg();
}
class EMail implements IReceive{
@Override
public void getMsg(){
System.out.println("接收到e-mail的消息");
}
}
class WeiXin implements IReceive{
@Override
public void getMsg() {
System.out.println("接收到微信消息");
}
}
接收到e-mail的消息
接收到微信消息
package com.zipeng.principle.dependenceinversionprinciple;
/**
* @author: zipeng Li
* 2021/4/18 18:42
*/
public class ImplType {
public static void main(String[] args) {
ChangHong changHong = new ChangHong();
IOpenAndClose openAndClose = new OpenAndClose();
openAndClose.open(changHong);
MeiDi meiDi = new MeiDi();
openAndClose.open(meiDi);
}
}
// 方式一:通过接口传递实现依赖
interface IOpenAndClose{
void open(ITV tv);
}
interface ITV{
void play();
}
class OpenAndClose implements IOpenAndClose{
@Override
public void open(ITV tv) {
tv.play();
}
}
class ChangHong implements ITV{
@Override
public void play() {
System.out.println("长虹电视机,打开");
}
}
class MeiDi implements ITV{
@Override
public void play() {
System.out.println("美的电视机打开");
}
}
长虹电视机,打开
美的电视机打开
package com.zipeng.principle.dependenceinversionprinciple;
/**
* @author: zipeng Li
* 2021/4/18 18:42
*/
public class ImplType {
public static void main(String[] args) {
ChangHong changHong = new ChangHong();
MeiDi meiDi = new MeiDi();
IOpenAndClose openAndClose = new OpenAndClose(changHong);
openAndClose.open();
openAndClose = new OpenAndClose(meiDi);
openAndClose.open();
}
}
// 方式二:通过构造方法传递依赖
interface IOpenAndClose{
void open();
}
interface ITV{
void play();
}
class OpenAndClose implements IOpenAndClose{
private ITV tv;
public OpenAndClose(ITV tv) {
this.tv = tv;
}
@Override
public void open() {
tv.play();
}
}
class ChangHong implements ITV{
@Override
public void play() {
System.out.println("长虹电视机,打开");
}
}
class MeiDi implements ITV{
@Override
public void play() {
System.out.println("美的电视机打开");
}
}
长虹电视机,打开
美的电视机打开
package com.zipeng.principle.dependenceinversionprinciple;
/**
* @author: zipeng Li
* 2021/4/18 18:42
*/
public class ImplType {
public static void main(String[] args) {
ChangHong changHong = new ChangHong();
MeiDi meiDi = new MeiDi();
IOpenAndClose openAndClose = new OpenAndClose();
openAndClose.setITV(changHong);
openAndClose.open();
openAndClose.setITV(meiDi);
openAndClose.open();
}
}
// 方式三:通过setter方法传递依赖
interface IOpenAndClose{
void open();
void setITV(ITV tv);
}
interface ITV{
void play();
}
class OpenAndClose implements IOpenAndClose{
private ITV tv;
@Override
public void open() {
tv.play();
}
@Override
public void setITV(ITV tv) {
this.tv = tv;
}
}
class ChangHong implements ITV{
@Override
public void play() {
System.out.println("长虹电视机,打开");
}
}
class MeiDi implements ITV{
@Override
public void play() {
System.out.println("美的电视机打开");
}
}
长虹电视机,打开
美的电视机打开
对继承的思考:
里氏替换原则
package com.zipeng.principle.lishireplace;
/**
* @author: zipeng Li
* 2021/4/24 21:22
*/
public class LishiReplace {
public static void main(String[] args) {
A a = new A();
System.out.println("11-3=" + a.func1(11,3));
System.out.println("1-8=" + a.func1(1,8));
System.out.println("===================");
B b = new B();
System.out.println("11-3=" + b.func1(11,3));
System.out.println("1-8=" + b.func1(1,8));
System.out.println("11+3+9=" + b.fun2(11,3));
}
}
class A{
public int func1(int num1, int num2){
return num1 - num2;
}
}
class B extends A{
@Override
public int func1(int num1, int num2) {
return num1 + num2;
}
public int fun2(int num1, int num2){
return func1(num1, num2) + 9;
}
}
11-3=8
1-8=-7
===================
11-3=14
1-8=9
11+3+9=23
package com.zipeng.principle.lishireplace.improve;
/**
* @author: zipeng Li
* 2021/4/25 21:28
*/
public class LishiReplace {
public static void main(String[] args) {
A a = new A();
System.out.println("11-3=" + a.func1(11,3));
System.out.println("1-8=" + a.func1(1,8));
System.out.println("===================");
B b = new B();
System.out.println("11+3=" + b.func1(11,3));
System.out.println("1+8=" + b.func1(1,8));
System.out.println("11+3+9=" + b.fun2(11,3));
// 使用组合
System.out.println("11-3=" + b.func3(11,3));
}
}
class Base{}
class A extends Base{
public int func1(int num1, int num2){
return num1 - num2;
}
}
class B extends Base {
private A a = new A();
public int func1(int num1, int num2) {
return num1 + num2;
}
public int fun2(int num1, int num2){
return func1(num1, num2) + 9;
}
public int func3(int num1, int num2){
return this.a.func1(num1, num2);
}
}
11-3=8
1-8=-7
===================
11+3=14
1+8=9
11+3+9=23
11-3=8
要实现开闭原则
package com.zipeng.principle.ocp;
/**
* @author: zipeng Li
* 2021/4/25 21:47
*/
public class Draw {
public static void main(String[] args) {
Drawer drawer = new Drawer();
drawer.draw(new Rectangle());
drawer.draw(new Circle());
}
}
// 绘图类
class Drawer{
public void draw(Shape s){
if(s.type == 1){
drawRectangle(s);
}else if(s.type == 2){
drawCircle(s);
}
}
public void drawRectangle(Shape s){
System.out.println("绘制矩形");
}
public void drawCircle(Shape s){
System.out.println("绘制圆形");
}
}
class Shape{
int type;
}
class Rectangle extends Shape{
public Rectangle() {
type = 1;
}
}
class Circle extends Shape{
public Circle() {
type = 2;
}
}
绘制矩形
绘制圆形
分析:
优点:比较好理解,简单易操作
缺点:违反设计模式的ocp原则。如需要新增加一个图形种类时,需要修改多处代码。
思路:把Shape类做成抽象类,并提供一个抽象的draw方法,让子类去实现。当有新的图形加入时,只需要让新的图形继承Shape,并实现draw方法。
package com.zipeng.principle.ocp.inprove;
/**
* @author: zipeng Li
* 2021/4/25 22:06
*/
public class Draw {
public static void main(String[] args) {
Drawer drawer = new Drawer();
drawer.draw(new Rectangle());
drawer.draw(new Circle());
}
}
// 绘图类
class Drawer{
public void draw(Shape s){
s.draw();
}
}
abstract class Shape{
public abstract void draw();
}
class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("绘制矩形");
}
}
class Circle extends Shape {
@Override
public void draw() {
System.out.println("绘制圆形");
}
}
最少知道原则
,即一个类对自己依赖的类知道的越少越好。也就是说,对被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public方法,不对外泄漏任何信息直接的朋友
:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,称出现成员变量、方法参数、方法返回值中的类为直接的朋友。而出现局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。package com.zipeng.principle.demeter;
import java.util.ArrayList;
import java.util.List;
/**
* @author: zipeng Li
* 2021/4/26 15:42
*/
public class Demeter {
public static void main(String[] args) {
//创建了一个 SchoolManager 对象
SchoolManager schoolManager = new SchoolManager();
//输出学院的员工id 和 学校总部的员工信息
schoolManager.printAllEmployee(new CollegeManager());
}
}
//学校总部员工类
class Employee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//学院的员工类
class CollegeEmployee {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
//管理学院员工的管理类
class CollegeManager {
//返回学院的所有员工
public List<CollegeEmployee> getAllEmployee() {
List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
CollegeEmployee emp = new CollegeEmployee();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}
}
//学校管理类
//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则
class SchoolManager {
//返回学校总部的员工
public List<Employee> getAllEmployee() {
List<Employee> list = new ArrayList<Employee>();
for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
Employee emp = new Employee();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
//该方法完成输出学校总部和学院员工信息(id)
void printAllEmployee(CollegeManager sub) {
//分析问题
//1. 这里的 CollegeEmployee 不是 SchoolManager的直接朋友
//2. CollegeEmployee 是以局部变量方式出现在 SchoolManager
//3. 违反了 迪米特法则
//获取到学院员工
List<CollegeEmployee> list1 = sub.getAllEmployee();
System.out.println("------------学院员工------------");
for (CollegeEmployee e : list1) {
System.out.println(e.getId());
}
//获取到学校总部员工
List<Employee> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工------------");
for (Employee e : list2) {
System.out.println(e.getId());
}
}
}
------------学院员工------------
学院员工id= 0
学院员工id= 1
学院员工id= 2
学院员工id= 3
学院员工id= 4
学院员工id= 5
学院员工id= 6
学院员工id= 7
学院员工id= 8
学院员工id= 9
------------学校总部员工------------
学校总部员工id= 0
学校总部员工id= 1
学校总部员工id= 2
学校总部员工id= 3
学校总部员工id= 4
上述设计的问题在于SchollManager
中,CollegeEmployee
类并不是SchoolManager
类的直接朋友
按照迪米特法则,应该避免类中出现这样非直接朋友关系的耦合
改进如下:
//管理学院员工的管理类
class CollegeManager {
//返回学院的所有员工
public List<CollegeEmployee> getAllEmployee() {
List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
CollegeEmployee emp = new CollegeEmployee();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}
public void printAllEmployee(){
//获取到学院员工
List<CollegeEmployee> list1 = this.getAllEmployee();
System.out.println("------------学院员工------------");
for (CollegeEmployee e : list1) {
System.out.println(e.getId());
}
}
}
//学校管理类
class SchoolManager {
//返回学校总部的员工
public List<Employee> getAllEmployee() {
List<Employee> list = new ArrayList<Employee>();
for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
Employee emp = new Employee();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
//该方法完成输出学校总部和学院员工信息(id)
void printAllEmployee(CollegeManager sub) {
sub.printAllEmployee(); // 把这里的代码段封装到CollegeManager内
//获取到学校总部员工
List<Employee> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工------------");
for (Employee e : list2) {
System.out.println(e.getId());
}
}
}
合成复用原则要求:尽量使用合成/聚合方式,而不是使用继承
【不好的方式】
【可选择的三种解决方案】
设计原则核心思想:
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
- 针对接口编程,而不是针对实现编程
- 为了交互对象之间的松耦合设计而努力
设计模式分为三种类型,共23种:
单例模式
、抽象工厂模式、原型模式、建造者模式、工厂模式
装饰模式
、组合模式、外观模式、享元模式、代理模式观察者模式
、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)