loong - 设计模式 - 七种设计原则
分类
- 单一职责原则
- 接口隔离原则
- 依赖倒置原则
- 里氏替换原则
- 开闭原则
- 迪米特法则
- 合成复用原则
单一职责原则
定义:
一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分。即,每个类只负责自己的事情,而不是变成万能
注意事项
- 降低类的复杂度,一个类只负责一项职责
- 提高类的可读性,可维护性
- 降低变更引起的风险
- 通常情况下,**我们应当遵守单一职责原则,**只有逻辑足够简单,才可以在代码级违反单一职责;只有在类中方法数量足够少,可以在方法上保持单一职责
示例
-
方案一
package com.learning.principle.singleresponsibility; /** * 方案一 * 1.违背了 单一职责 飞机不应该在陆地上行驶 * * @author nieshenglei */ public class SingleResponsibility1 { public static void main(String[] args) { Vehicle vehicle = new Vehicle(); vehicle.run("摩托车"); vehicle.run("汽车"); vehicle.run("飞机"); } } /** * 交通工具类 */ class Vehicle { public void run(String vehicle) { System.out.println(vehicle + " 在公路上行驶"); } }
-
方案二
package com.learning.principle.singleresponsibility; /** * 方案二 分析 * 1. 遵守了单一职责 * 2.但是 改动大 原类Vehicle被修改 客户端也要跟着修改 这时候可以考虑 方案三 在方法层面遵守单一职责 * * @author nieshenglei */ public class SingleResponsibility2 { //客户端 public static void main(String[] args) { RoadVehicle roadVehicle = new RoadVehicle(); roadVehicle.run("摩托车"); roadVehicle.run("汽车"); AirVehicle airVehicle = new AirVehicle(); airVehicle.run("飞机"); } } /** * 公路上跑的交通工具类 */ class RoadVehicle { public void run(String vehicle) { System.out.println(vehicle + " 在公路上行驶"); } } /** * 空中的交通工具类 */ class AirVehicle { public void run(String vehicle) { System.out.println(vehicle + " 在天空飞行"); } } /** * 水中的交通工具类 */ class WaterVehicle { public void run(String vehicle) { System.out.println(vehicle + " 在水中行驶"); } }
-
方案三
package com.learning.principle.singleresponsibility; /** * 方案三 * 1. 在类的层面上 没有完全遵守单一职责 * 2. 在方法级别上遵守了 单一职责 * * 对比 方案二 类中方法少 其实可以使用 方案三 在方法层面遵守单一职责 但是如果后期的交通工具类不断扩大 建议使用方案二 拆分 * * @author nieshenglei */ public class SingleResponsibility3 { //客户端 public static void main(String[] args) { CommentVehicle vehicle = new CommentVehicle(); vehicle.runRoad("摩托车"); vehicle.runRoad("汽车"); vehicle.runAir("飞机"); vehicle.runWater("轮船"); } } /** * 交通工具类 */ class CommentVehicle { /** * 陆地交通工具 * * @param vehicle 交通工具 */ public void runRoad(String vehicle) { System.out.println(vehicle + " 在公路上行驶"); } /** * 空中交通工具 * * @param vehicle 交通工具 */ public void runAir(String vehicle) { System.out.println(vehicle + " 在空中行驶"); } /** * 水中交通工具 * * @param vehicle 交通工具 */ public void runWater(String vehicle) { System.out.println(vehicle + " 在水上行驶"); } }
接口隔离原则
定义:
- 客户端不应该依赖它不需要的接口;
- 一个类对另一个类的依赖应该建立在最小的接口上。
概括的说就是:建立单一接口,不要建立臃肿庞大的接口。(接口尽量细化,同时接口中的方法尽量少。)
实例一(不符合原则)
UML类图
代码
package com.learning.principle.segregation;
/**
* @author nieshenglei
*/
public class Segregation1 {
/**
* 客户端
* @param args 入参
*/
public static void main(String[] args) {
A a = new A();
B b = new B();
a.depend1(b);
a.depend2(b);
a.depend3(b);
C c = new C();
D d = new D();
c.depend1(d);
c.depend4(d);
c.depend5(d);
}
}
interface Interface1 {
/**
* 方法1
*/
void opreation1();
/**
* 方法2
*/
void opreation2();
/**
* 方法3
*/
void opreation3();
/**
* 方法4
*/
void opreation4();
/**
* 方法5
*/
void opreation5();
}
/**
* B 类
*/
class B implements Interface1{
/**
* 方法1
*/
@Override
public void opreation1() {
System.out.println("B 实现了 Interface1接口 的 opreation1 方法");
}
/**
* 方法2
*/
@Override
public void opreation2() {
System.out.println("B 实现了 Interface1接口 的 opreation2 方法");
}
/**
* 方法3
*/
@Override
public void opreation3() {
System.out.println("B 实现了 Interface1接口 的 opreation3 方法");
}
/**
* 方法4
*/
@Override
public void opreation4() {
System.out.println("B 实现了 Interface1接口 的 opreation4 方法");
}
/**
* 方法5
*/
@Override
public void opreation5() {
System.out.println("B 实现了 Interface1接口 的 opreation5 方法");
}
}
/**
* D 类
*/
class D implements Interface1{
/**
* 方法1
*/
@Override
public void opreation1() {
System.out.println("D 实现了 Interface1接口 的 opreation1 方法");
}
/**
* 方法2
*/
@Override
public void opreation2() {
System.out.println("D 实现了 Interface1接口 的 opreation2 方法");
}
/**
* 方法3
*/
@Override
public void opreation3() {
System.out.println("D 实现了 Interface1接口 的 opreation3 方法");
}
/**
* 方法4
*/
@Override
public void opreation4() {
System.out.println("D 实现了 Interface1接口 的 opreation4 方法");
}
/**
* 方法5
*/
@Override
public void opreation5() {
System.out.println("D 实现了 Interface1接口 的 opreation5 方法");
}
}
/**
* A类 通过接口 Interface1 依赖使用B类,但是只会用到 1 2 3 方法
*/
class A{
public void depend1(Interface1 interface1){
interface1.opreation1();
}
public void depend2(Interface1 interface1){
interface1.opreation3();
}
public void depend3(Interface1 interface1){
interface1.opreation3();
}
}
/**
* C 类 通过接口 Interface1 依赖使用B类,但是只会用到 1 4 5 方法
*/
class C{
public void depend1(Interface1 interface1){
interface1.opreation1();
}
public void depend4(Interface1 interface1){
interface1.opreation4();
}
public void depend5(Interface1 interface1){
interface1.opreation5();
}
}
实例二(符合隔离原则)
UML
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9jejseuj-1680739281760)(…/Z-md_image/%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E5%8E%9F%E5%88%99%E5%AE%9E%E4%BE%8B%E4%BA%8C%E5%9B%BE%E5%83%8F.png)]
代码
package com.learning.principle.segregation;
/**
* 接口隔离原则 正确示例
* <p/>
* 将 原有的 Interface1 接口 拆分成 Interface11(方法一) Interface22(方法二,方法三) Interface33(方法四,方法五)
* <p/>
* B 类实现了 接口 Interface11 Interface22 <br>
* A 类通过 接口 Interface11 Interface22 接口 依赖 B 类(方法一 二 三)<br>
*
* D类实现了 接口 Interface11 Interface22 <br>
* C类通过 接口 Interface11 Interface33 接口 依赖 D类(方法 一 四 五)<br>
*
* @author nieshenglei
*/
public class Segregation2 {
/**
* 客户端
* @param args 入参
*/
public static void main(String[] args) {
A1 a1 = new A1();
B1 b1 = new B1();
a1.depend1(b1);
a1.depend2(b1);
a1.depend3(b1);
C1 c1 = new C1();
D1 d1 = new D1();
c1.depend1(d1);
c1.depend4(d1);
c1.depend5(d1);
}
}
interface Interface11 {
/**
* 方法1
*/
void opreation1();
}
interface Interface22 {
/**
* 方法2
*/
void opreation2();
/**
* 方法3
*/
void opreation3();
}
interface Interface33 {
/**
* 方法4
*/
void opreation4();
/**
* 方法5
*/
void opreation5();
}
/**
* B1 类 Interface11 * B1 类
*/
class B1 implements Interface11, Interface22{
/**
* 方法1
*/
@Override
public void opreation1() {
System.out.println("B1 实现了 Interface11接口 的 opreation1 方法");
}
/**
* 方法2
*/
@Override
public void opreation2() {
System.out.println("B1 实现了 Interface22接口 的 opreation2 方法");
}
/**
* 方法3
*/
@Override
public void opreation3() {
System.out.println("B1 实现了 Interface22接口 的 opreation3 方法");
}
}
/**
* D1 类 实现了 Interface11 Interface33
*/
class D1 implements Interface11,Interface33{
/**
* 方法1
*/
@Override
public void opreation1() {
System.out.println("D1 实现了 Interface11接口 的 opreation1 方法");
}
/**
* 方法4
*/
@Override
public void opreation4() {
System.out.println("D1 实现了 Interface33接口 的 opreation4 方法");
}
/**
* 方法5
*/
@Override
public void opreation5() {
System.out.println("D1 实现了 Interface33接口 的 opreation5 方法");
}
}
/**
* A1类 通过接口 Interface11 Interface22 依赖使用B类,但是只会用到 1 2 3 方法
*/
class A1{
public void depend1(Interface11 interface11){
interface11.opreation1();
}
public void depend2(Interface22 interface22){
interface22.opreation3();
}
public void depend3(Interface22 interface22){
interface22.opreation3();
}
}
/**
* C1 类 通过接口 Interface11 Interface33 依赖使用B类,但是只会用到 1 4 5 方法
*/
class C1{
public void depend1(Interface11 interface11){
interface11.opreation1();
}
public void depend4(Interface33 interface33){
interface33.opreation4();
}
public void depend5(Interface33 interface33){
interface33.opreation5();
}
}
依赖倒置原则
定义
- 高层模块不应该依赖低层模块,二者都应该依赖其抽象**(抽象是指接口或抽象类)**
- 抽象不应该依赖细节**(细节是指实现类)**
- 细节应该依赖抽象
- 核心思想:面向接口编程
实例一(不符合原则)
package com.learning.principle.inversion;
/**
* 依赖倒置原则 示例
*
* @author nieshenglei
*/
public class DependencyInversion1 {
//客户端
public static void main(String[] args) {
Person1 person1 = new Person1();
person1.receive(new Email1());
}
}
/**
* 邮件类
*/
class Email1{
public String getInfo(){
return "电子邮件信息: hello,world";
}
}
/**
* 方式一
* 完成Person接收邮件
* <br>
* 分析
* 1.实现简单
* 2.如果我们获取的消息类型是其他类型 如 微信 短息 QQ 则需要新增类,同时Person也要
* 增加相应的接受方法
* <p>
* 解决思路:引入一个抽象的接口IReceiver,表示接收者,让Person类与接口IReceiver发生依赖
* 因为 Email,微信,QQ属于接收的范围,他们各自实现IReceiver接口就可以,使此案例符合依赖倒置原则
* </p>
*
*
*/
class Person1{
/**
* 接收消息
* @param email 邮件消息
*/
public void receive(Email1 email){
System.out.println(email.getInfo());
}
}
实例二
package com.learning.principle.inversion;
/**
* 依赖倒置原则 示例
*
* @author nieshenglei
*/
public class DependencyInversion2 {
//客户端
public static void main(String[] args) {
//相比 方式一 客户端不需要改动
Person2 person = new Person2();
person.receive(new Email2());
//增加微信接受
person.receive(new WeiXin());
}
}
/**
* 接受消息接口
*/
interface IReceiver{
/**
* 接受消息
* @return 返回消息内容
*/
public String getInfo();
}
/**
* 邮件类 实现了 IReceiver 接口
*/
class Email2 implements IReceiver{
@Override
public String getInfo(){
return "电子邮件信息: hello,world";
}
}
class WeiXin implements IReceiver{
/**
* 接受消息
*
* @return 返回消息内容
*/
@Override
public String getInfo() {
return "微信消息内容: 叮咚,有人发消息给你啦!";
}
}
/**
* 方式二
* 完成Person接收邮件
* <br>
* 和IReceiver接口耦合,不和具体的消息发生耦合,使其能接收各种消息 例如 微信
*
*/
class Person2{
/**
* 接收消息
* @param iReceiver 邮件消息
*/
public void receive(IReceiver iReceiver){
System.out.println(iReceiver.getInfo());
}
}
扩展:依赖传递三种方式
- 通过接口传递
- 通过构造器传递
- 通过setter方法传递
里氏替换原则
定义
- 子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
- 提高代码的重用性;
实例一(不符合规则)
package com.learning.principle.liskov;
/**
* 里氏替换原则 示例一
*
* 示例弊端:B1类重写的父类A1类的func1()方法,造成原有功能出现错误
*
* @author nieshenglei
*/
public class Liskov1 {
//客户端
public static void main(String[] args) {
A1 a1 = new A1();
System.out.println("11-3 = "+a1.func1(11, 3));
System.out.println("1-8 = "+a1.func1(1, 8));
System.out.println("----------------------------------");
B1 b1 = new B1();
//重写了父类的方法,导致计算减法失败,真正使用的是子类重写后的方法
System.out.println("11-3 = "+b1.func1(11, 3));
System.out.println("1-8 = "+b1.func1(1, 8));
System.out.println("11+3+9 = "+b1.func2(11, 3));
}
}
/**
* A 类
*/
class A1{
/**
* 返回两个数的差
* @param num1 入参1
* @param num2 入参2
* @return 返回一个int类型
*/
public int func1(int num1,int num2){
return num1-num2;
}
}
/**
* B 类 继承 A 类
*
*/
class B1 extends A1{
/**
* 此方法 重写 A1的方法
*
* 返回两个整型的和
* @param a 入参1
* @param b 入参2
* @return 返回一个int类型
*/
public int func1(int a,int b){
return a+b;
}
/**
* 两个整型的求和,并+9
* @param a 入参1
* @param b 入参2
* @return 返回一个int类型
*/
public int func2(int a,int b){
return func1(a, b)+9;
}
}
示例二(符合规则)
package com.learning.principle.liskov;
/**
* 里氏替换原则 示例二
*
* 类 A2 B2 都继承 Base 使 基础方法func1() 不受影响
*
* @author nieshenglei
*/
public class Liskov2 {
//客户端
public static void main(String[] args) {
A2 a2 = new A2();
System.out.println("11-3 = "+a2.func1(11, 3));
System.out.println("1-8 = "+a2.func1(1, 8));
System.out.println("----------------------------------");
B2 b2 = new B2();
System.out.println("11+3 = "+b2.func1(11, 3));
System.out.println("1-8 = "+b2.func1(1, 8));
System.out.println("11+3+9 = "+b2.func2(11, 3));
//使用组合,仍然可以使用到A1的func1()方法
System.out.println("8-1 = "+b2.func3(8, 1));
}
}
/**
* 定义 一个 基类 将公共的属性和方法放在基类中
*/
class Base{
}
/**
* A 类
*/
class A2 extends Base{
/**
* 返回两个数的差
* @param num1 入参1
* @param num2 入参2
* @return 返回一个int类型
*/
public int func1(int num1,int num2){
return num1-num2;
}
}
/**
* B 类 继承 A 类
*
*/
class B2 extends Base{
//加入B2 仍然需要A2类的方法,可以使用组合关系
private A2 a2 = new A2();
/**
*
* 返回两个整型的和
* @param a 入参1
* @param b 入参2
* @return 返回一个int类型
*/
public int func1(int a,int b){
return a+b;
}
/**
* 两个整型的求和,并+9
* @param a 入参1
* @param b 入参2
* @return 返回一个int类型
*/
public int func2(int a,int b){
return func1(a, b)+9;
}
public int func3(int a,int b){
return a2.func1(a, b);
}
}
开闭原则
定义
- 一个软件实体如类,模块和函数应该
对扩展开放(对提供方),对修改关闭(对使用方)
。用抽象构建框架,用实现扩展细节。 - 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
- 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
示例一(不符合原则)
package com.learning.principle.ocp;
/**
* 开闭原则 实例一
* 优点:好理解,容易操作
* 缺点:违反了开闭原则(对扩展开放(提供方),对修改关闭(使用方)),即当我们给类
* 新增功能时,尽量不要修改代码,或者尽可能少修改代码
* 比如我们新增的图形类 三角形
*
*
* @author nieshenglei
*/
public class Ocp1 {
//客户端
public static void main(String[] args) {
GraphicEditor graphicEditor = new GraphicEditor();
graphicEditor.drawShape(new Rectangle());
graphicEditor.drawShape(new Circle());
//绘制三角形
graphicEditor.drawShape(new Triangle());
}
}
/**
* 图形绘制类 服务使用方
*/
class GraphicEditor{
/**
* 根据传入的类型 绘制不同图形
* @param shape 传入的图形类型
*/
public void drawShape(Shape shape){
if(shape.mType == 1){
drawRectangle(shape);
} else if (shape.mType==2) {
drawCircle(shape);
} else if (shape.mType==3) {
//新增绘制图形判断
drawTriangle(shape);
}
}
/**
* 绘制 矩形的方法
* @param shape 图形类
*/
public void drawRectangle(Shape shape){
System.out.println("绘制矩形 类型值:"+shape.mType);
}
/**
* 绘制 圆形的方法
* @param shape 图形类
*/
public void drawCircle(Shape shape){
System.out.println("绘制圆形 类型值:"+shape.mType);
}
/**
* 新增 绘制三角形 绘制方法
*/
public void drawTriangle(Shape shape){
System.out.println("绘制三角形 类型值:"+shape.mType);
}
}
/**
* 图形基类 服务提供方
*/
class Shape{
int mType;
}
/**
* 矩形类 服务提供方
*/
class Rectangle extends Shape{
public Rectangle() {
super.mType=1;
}
}
/**
* 圆形类 服务提供方
*/
class Circle extends Shape{
public Circle() {
super.mType=2;
}
}
/**
* 新增图形 三角形 服务提供方
*/
class Triangle extends Shape{
public Triangle() {
super.mType=3;
}
}
示例二
package com.learning.principle.ocp;
/**
* 开闭原则 实例二
* 将 Shape(服务提供方) 修改为 抽象类 并定义抽象方法 是其子类实现其方法
* GraphicEditor2 (服务使用方) 只需要传入想绘制的图形,并调用图形的绘制方法,就可以实现功能的拓展
*
* 做到了 对扩展开放 对修改关闭
*
* @author nieshenglei
*/
public class Ocp2 {
//客户端
public static void main(String[] args) {
GraphicEditor2 graphicEditor = new GraphicEditor2();
graphicEditor.drawShape(new Rectangle2());
graphicEditor.drawShape(new Circle2());
//绘制三角形
graphicEditor.drawShape(new Triangle2());
}
}
/**
* 图形绘制类 服务使用方
*/
class GraphicEditor2{
/**
* 根据传入的类型 绘制不同图形
* @param shape 传入的图形类型
*/
public void drawShape(Shape2 shape){
shape.draw();
}
}
/**
* 图形基类 服务提供方
*/
abstract class Shape2{
int mType;
/**
* 定义抽象方法
*/
public abstract void draw();
}
/**
* 矩形类 服务提供方
*/
class Rectangle2 extends Shape2{
public Rectangle2() {
super.mType=1;
}
/**
* 定义抽象方法
*/
@Override
public void draw() {
System.out.println("绘制 矩形 类型值:"+mType);
}
}
/**
* 圆形类 服务提供方
*/
class Circle2 extends Shape2{
public Circle2() {
super.mType=2;
}
/**
* 定义抽象方法
*/
@Override
public void draw() {
System.out.println("绘制 圆形 类型值:"+mType);
}
}
/**
* 新增图形 三角形 服务提供方
*/
class Triangle2 extends Shape2{
public Triangle2() {
super.mType=3;
}
/**
* 定义抽象方法
*/
@Override
public void draw() {
System.out.println("绘制三角形 类型值:"+mType);
}
}
迪米特法则
定义:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
-
通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。
-
迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。
-
我们应该尽量降低与非直接朋友通信,而不是绝对不通信
示例一(不遵守规则)
package com.learning.principle.demeter;
import java.util.ArrayList;
import java.util.List;
/**
* 迪米特原则 示例一
* 违反了 迪米特原则 原因 以 SchoolManager类 分析 存在 非直接朋友 CollegeEmployee,Employee
*
* @author nieshenglei
*/
public class Demeter1 {
/**
* 客户端
* @param args
*/
public static void main(String[] args) {
SchoolManager schoolManager = new SchoolManager();
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++) {
CollegeEmployee emp = new CollegeEmployee();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}
}
/**
* 学校管理者
*
* 直接朋友
* 方法参数 Employee,
* 方法返回值 CollegeManager
*
* 非直接朋友
* 局部变更 CollegeEmployee
*
*
*/
class SchoolManager {
public List<Employee> getAllEmployee() {
List<Employee> list = new ArrayList<Employee>();
for (int i = 0; i < 5; i++) {
Employee emp = new Employee();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
/**
* 输出所有 人员信息
* @param sub 学院管理者
*/
void printAllEmployee(CollegeManager sub) {
//输出学院员工信息
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());
}
}
}
示例二(遵守规则)
package com.learning.principle.demeter;
import java.util.ArrayList;
import java.util.List;
/**
* 迪米特原则 示例二
*
* 改进思路:
* 以 SchoolManager1 类 为例,将其方法printAllEmployee() 关于 CollegeEmployee1
* 输出 员工信息的代码 封装成 单独的方法 放入 CollegeEmployee1类中,在SchoolManager1 中直接调用
*
*
* @author nieshenglei
*/
public class Demeter2 {
/**
* 客户端
* @param args
*/
public static void main(String[] args) {
SchoolManager1 schoolManager = new SchoolManager1();
schoolManager.printAllEmployee(new CollegeManager1());
}
}
/**
* 学校总部员工类
*/
class Employee1 {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
/**
* 学院员工类
*/
class CollegeEmployee1 {
private String id;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
/**
* 学院管理者
*/
class CollegeManager1 {
/**
* 创建 员工
* @return
*/
public List<CollegeEmployee1> getAllEmployee() {
List<CollegeEmployee1> list = new ArrayList<CollegeEmployee1>();
for (int i = 0; i < 10; i++) {
CollegeEmployee1 emp = new CollegeEmployee1();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}
public void printEmployee(){
//输出学院员工信息
List<CollegeEmployee1> list1 = this.getAllEmployee();
System.out.println("------------学院员工信息------------");
for (CollegeEmployee1 e : list1) {
System.out.println(e.getId());
}
}
}
/**
* 学校管理者
*
* 直接朋友
* 方法参数 Employee1
* 方法返回值 CollegeManager1
*
*/
class SchoolManager1 {
public List<Employee1> getAllEmployee() {
List<Employee1> list = new ArrayList<Employee1>();
for (int i = 0; i < 5; i++) {
Employee1 emp = new Employee1();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
/**
* 输出所有 人员信息
* @param sub 学院管理者
*/
void printAllEmployee(CollegeManager1 sub) {
sub.printEmployee();
//输出学校总部信息
List<Employee1> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工信息------------");
for (Employee1 e : list2) {
System.out.println(e.getId());
}
}
}
合成复用原则
定义
-
尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的。
-
聚合has-A和组合contains-A。
-
优点:可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
ollegeEmployee1> getAllEmployee() {
List list = new ArrayList();
for (int i = 0; i < 10; i++) {
CollegeEmployee1 emp = new CollegeEmployee1();
emp.setId("学院员工id= " + i);
list.add(emp);
}
return list;
}public void printEmployee(){
//输出学院员工信息
List list1 = this.getAllEmployee();
System.out.println(“------------学院员工信息------------”);
for (CollegeEmployee1 e : list1) {
System.out.println(e.getId());
}
}
}
/**
- 学校管理者
- 直接朋友
- 方法参数 Employee1
- 方法返回值 CollegeManager1
*/
class SchoolManager1 {
public List getAllEmployee() {
List list = new ArrayList();
for (int i = 0; i < 5; i++) {
Employee1 emp = new Employee1();
emp.setId("学校总部员工id= " + i);
list.add(emp);
}
return list;
}
/**
- 输出所有 人员信息
* @param sub 学院管理者
*/
void printAllEmployee(CollegeManager1 sub) {
sub.printEmployee();
//输出学校总部信息
List<Employee1> list2 = this.getAllEmployee();
System.out.println("------------学校总部员工信息------------");
for (Employee1 e : list2) {
System.out.println(e.getId());
}
}
}
## 合成复用原则
**定义**
- 尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的。
- 聚合has-A和组合contains-A。
- 优点:可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。