"万丈高楼平地起,7种模式打地基",模式是一种规范,我们应该站在巨人的肩膀上越看越远,接下来,让我们去仔细了解了解面向对象的7种设计模式
7种设计模式
设计原则的核心思想:
找出应用中可能需要变化之处,独立出来,不要和不需要变化的代码混在一起
针对接口编程,而坏是针对实现编程
为了交互对象的耦合性而设计
为了使程序高内聚,低耦合
单一职责(低耦合,高内聚)
每一个类负责的任务很明确,降低代码之间的耦合度,如果代码耦合度较高,动一点则要动全身,当变化发生时设计或遭受到意想不到的破坏
public class Run {
public void run(){
System.out.println("跑步");
}
}
在Run类中只负责了Run()的功能,不负责其他的功能,在设计改变类的时候对整体的影响不大
开闭原则(适应性和灵活性 稳定性和延续性 可复用性和可维护性)
在软件开发的过程中,随着版本的更替,软件的需求会越来越多,如果是修改的内容的话,会很费时,但是我们换个思路,如果在设计模式的时候,我们可以先评估出最容易发生的类,然后对其进行抽象化设计,当变化发生时,只需要增加新的具体类来实现新的业务功能
未使用开/闭原则:
/*
开闭原则引入案例
*/
public class CarDemo {
public static void main(String[] args) {
new CarFactory().createCar(1);
new CarFactory().createCar(2);
new CarFactory().createCar(3);
//后期如果需要添加车型,CarFactory需要修改代码
//new CarFactory().createCar(4);
//new CarFactory().createCar(5);
}
}
/*
汽车工程类,专门负责造汽车
*/
class CarFactory{
/*
违反了开闭原则,后期如果添加新的汽车类,则需要修改代码
*/
public void createCar(int type){
if(type==1){
System.out.println("造宝马汽车"+new Car("宝马汽车"));
}else if(type==2){
System.out.println("造奥迪汽车"+new Car("奥迪汽车"));
}else{
System.out.println("造大众汽车"+new Car("大众汽车"));
}
}
}
/*
Car类
*/
class Car{
String name;//定义了一个成员变量
public Car(String name) {//有参构造函数
this.name = name;
}
}
使用开/闭原则:
/*
开闭原则案例
*/
class CarDemo{
public static void main(String[] args) {
new CarFactory().carfactory(new BMW());
new CarFactory().carfactory(new Aodi());
new CarFactory().carfactory(new DaZhong());
}
}
//创建一个CarFactory类
class CarFactory{
//创建一个车辆工厂的方法
void carfactory(Car car){
car.createCar();
}
}
//创建一个抽象类Car
abstract class Car{
//创建一个创建车辆的抽象方法
public abstract void createCar();
}
/*
如果想添加车辆型号的话,只需要创建一个类继承Car类并实现createCar()方法,不用修改代码
*/
//继承并重写Car里的方法
class BMW extends Car{
@Override
public void createCar() {
System.out.println("造宝马汽车");
}
}
//继承并重写Car里的方法
class Aodi extends Car{
@Override
public void createCar() {
System.out.println("造奥迪汽车");
}
}
//继承并重写Car里的方法
class DaZhong extends Car{
@Override
public void createCar() {
System.out.println("造大众汽车");
}
}
//继承并重写Car里的方法
class BC extends Car{
@Override
public void createCar() {
System.out.println("造奔驰汽车");
Calendar.getInstance();
new GregorianCalendar();
}
}
里氏替换原则(提高代码的复用性、提高代码的可扩展性 | 继承是具有侵入性的 增大了耦合性 )
基本概念:继承必须确保超类锁拥有的性质在子类中仍然成立(子类继承父类后,尽量不要重写父类的方法,可以新增扩展其他的功能.保证子类功能的正确性. 不能让功能修改后,导致程序出错)
主要作用:
里氏替换原则是实现开闭原则的重要方式之一
克服了继承中重写父类方法造成的可复用性变差的缺点
功能正确的保证
加强了程序的健壮性,提高了程序的维护性降低需求变更时引入的风险
代码演练:
/*
里氏替换原则演示案例
计算器父类
*/
public class CalculatorDemo{
public static void main(String[] args) {
System.out.println(new SuperCalculator().sum(5,5,5));
}
}
//计算器 基类
class Calculator {
//加法
public int add(int a,int b){
return a+b;
}
//减法
public int sub(int a,int b){
return a-b;
}
}
/*
超级计算器子类
*/
class SuperCalculator extends Calculator{
//重写了父类加法
@Override
public int add(int a, int b) {
return a+b+5;
}
//求和方法 子类新增的功能
public int sum(int a,int b,int c){
//调用add(),但是子类重写了父类方法,此处调用的子类方法发生了变化
int result = this.add(a,b);
return result+c;
}
}
没有重写父类方法时,输出还是正确结果15,但是重写之后却改变了值,输出了错误的结果20
依赖倒置(都依赖于抽象)
让程序面向抽象类编程、面向接口编程(依赖于抽象接口,对抽象进行编程)
/*
依赖倒置引入案例
*/
public class WorkerDemo{
public static void main(String[] args) {
new Worker().getMessage(new DingDing());
new Worker().getMessage(new WeChat());
//每创建一个信息都要进行修改代码
}
}
class Worker {
public void getMessage(DingDing ding){
System.out.println(ding.sendMessage());
}
public void getMessage(WeChat weChat){
System.out.println(weChat.sendMessage());
}
//每添加一个信息都要进行修改代码
}
//钉钉消息
class DingDing{
public String sendMessage(){
return "钉钉消息";
}
}
//微信消息
class WeChat{
public String sendMessage(){
return "微信消息";
}
}
/*
依赖倒置案例演示
*/
public class WorkerDemo{
public static void main(String[] args) {
new Worker().getMessage(new WeChat());//具有可变性,有较高的适用性
}
}
class Worker {
public void getMessage(Message message){
System.out.println(message.sendMessage());
}
}
interface Message{
public String sendMessage();
}
//添加一个信息需要创建一个类实现Message接口
class WeChat implements Message{
@Override
public String sendMessage() {
return "微信消息";
}
}
class DingDing implements Message{
@Override
public String sendMessage() {
return "钉钉消息";
}
}
接口隔离
使用多个接口,不使用单一的总接口(这个最好理解,在这里就不解释了)
迪米特原则
一个对象应该对其他对象有最少的了解(在一个类中,应尽量少的使用与其没有直接关系的类)
直接关系:
类中的成员属性
在类中的方法作为参数使用
在类中的方法作为返回值类型
注意事项:
核心是降低类之间的耦合
从被依赖折者的角度来看,尽量将逻辑封装在类的内部,对外除了提供的public方法,不泄露任何信息
从依赖者的角度来说,只依赖应该依赖的对象
切记不要为了用而用
代码实现:
public class Demeter {
public static void main(String[] args) {
new SchoolManger().printAllEmployee(new CollegeManger());
}
}
/*
学校员工类
*/
class SchoolEmployee{
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 CollegeManger{
//生成学院所有的员工
public List<CollegeEmployee> getCollegeEmployee(){
ArrayList<CollegeEmployee> collegeEmployeeArrayList = new ArrayList<>();
for (int i = 0; i <10 ; i++) {
CollegeEmployee collegeEmployee = new CollegeEmployee();
collegeEmployee.setId("学院员工的id="+i); //添加学院员工
collegeEmployeeArrayList.add(collegeEmployee);
}
return collegeEmployeeArrayList;
}
}
//学校员工管理类
class SchoolManger {
//生成学校的员工
public List<SchoolEmployee> getSchoolEmployee() {
ArrayList<SchoolEmployee> employeeArrayList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
SchoolEmployee employee = new SchoolEmployee();
employee.setId("学校的员工id=" + i);
employeeArrayList.add(employee);
}
return employeeArrayList;
}
//输出学校员工和学院员工信息
public void printAllEmployee(CollegeManger collegeManger) {
//获取到学校员工
List<SchoolEmployee> employeeArrayList = this.getSchoolEmployee();
System.out.println("--------学校员工--------");
for (SchoolEmployee employee1 : employeeArrayList) {
System.out.println(employee1.getId());
}
System.out.println("--------学院员工--------");
List<CollegeEmployee> collegeEmployees = collegeManger.getCollegeEmployee();
//此处学校管理类中出现CollegeEmployee,此类与SchoolManger并非直接朋友,不合理
for (CollegeEmployee collegeEmployee : collegeEmployees) {
System.out.println(collegeEmployee.getId());
}
}
}
public class Demeter {
public static void main(String[] args) {
new SchoolManger().printAllEmployee(new CollegeManger());
}
}
/*
学校员工类
*/
class SchoolEmployee{
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 CollegeManger{
//生成学员所有的员工
public List<CollegeEmployee> getCollegeEmployee(){
ArrayList<CollegeEmployee> collegeEmployeeArrayList = new ArrayList<>();
for (int i = 0; i <10 ; i++) {
CollegeEmployee collegeEmployee = new CollegeEmployee();
collegeEmployee.setId("学院员工的id="+i); //添加学院员工
collegeEmployeeArrayList.add(collegeEmployee);
}
return collegeEmployeeArrayList;
}
public void printCollegeEmployee(){
List<CollegeEmployee> collegeEmployee = getCollegeEmployee();
for (CollegeEmployee employee : collegeEmployee) {
System.out.println("学员员工id="+employee.getId());
}
}
}
//学校员工管理类
class SchoolManger {
//生成学校的员工
public List<SchoolEmployee> getSchoolEmployee() {
ArrayList<SchoolEmployee> employeeArrayList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
SchoolEmployee employee = new SchoolEmployee();
employee.setId("学校的员工id=" + i);
employeeArrayList.add(employee);
}
return employeeArrayList;
}
//输出学校员工和学院员工信息
public void printAllEmployee(CollegeManger collegeManger) {
//获取到学校员工
List<SchoolEmployee> employeeArrayList = this.getSchoolEmployee();
System.out.println("--------学校员工--------");
for (SchoolEmployee employee1 : employeeArrayList) {
System.out.println(employee1.getId());
}
//CollegeManger与SchoolManger是直接朋友,相互之间访问
System.out.println("--------学员员工-----------");
collegeManger.printCollegeEmployee();
}
}
组合/聚合复用原则(优先使用组合,使系统更灵活,其次才考虑继承,达到复用的目的)
代码实现:
/*
组合/聚合复用原则案例1 使用依赖实现复用
*/
public class A {
public void method01() {
}
public void method02() {
}
}
class B extends A {
private A a;
public void method() {
}
}
class Test {
public static void main(String[] args) {
new B().method01();
new B().method02();
}
}
/*
组合/聚合复用原则案例2 使用组合/聚合实现复用
*/
public class A {
public void method01(){
}
public void method02(){
}
}
class B{
A a;
public void setA(A a){
this.a = a;
}
public void use(){
a.method01();
a.method02();
}
}
class Test{
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setA(a);
b.use();
}
}
/*
组合/聚合复用原则案例3 使用依赖实现复用
*/
public class A {
public void method01(){
}
public void method02(){
}
}
class B{
public void use(A a){
a.method01();
a.method02();
}
}
class Test{
public static void main(String[] args) {
A a = new A();
B b = new B();
b.use(a);
}
}