banner
NEWS LETTER

设计模式之 “一人设计九人慌”

Scroll down

设计模式的分类

根据目的分类

创建型模式

​ 用于描述”怎样创建对象“,他的主要特点是将对象的创建与使用分离

​ 单例、原型、工厂方法、抽象工厂、建造者等物种创建型模式

结构型模式

​ 用于描述如何将类或对象按某种布局组成更大的结构

​ 代理、适配器、桥接、装饰、外观、享元、组合等7种构造型模式

行为型模式

​ 用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责

​ 模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等11种

根据作用分类

(1)类模式:

​ 用于处理类与子类之间的继承关系,这些关系是静态的。

​ GoF中的工厂方法、(类)适配器、模板方法、解释器属于该模式

(2)对象模式:

​ 用于处理对象之间的组合或聚合关系,具动态性。除了上述四种模式,都是对象

UML类图表示法

类的表示方式

​ 在UML类图中,类使用包含类名、属性(field)和方法(method)且带有分割线的矩形表示,比如下面表示一个Employee类,它包含name、age和address这三个属性以及word方法

Employee
-name:String -age:int -address:String
+work():void

​ 属性/方法名称前加的加号和减号表示这个属性/方法的可见性,UML图中表示可见性的符号有三种:

​ +:表示public

​ -:表示private

​ #:表示protected

类与类之间的关系

关联关系

单向关联和双向关联

例如,一个学生选修一门特定的课程是学生类Student和课程类Course之间的一个关联,而一个教师教授一门课程是师资类Faculty和课程类Course之间的一个关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Student {
private Course[] courses;


public void addCourse(Course s) {

}
}


public class Course {
private Strudent[] students;
private Faculty faculty;

public void addStudent(Student s) {

}

public void setFaculty(Faculty faculty) {
this.faculty = faculty;
}
}


public class Faculty {
private Course[] courses;

public void addCourse(Course s) {

}
}

聚合

聚合是强关联关系,是整体和部分的关系

例如,一个公司有很多员工就是公司类Company和员工类Employee之间的一种聚合关系。被聚合对象和聚合对象有着各自的生命周期,即如果公司倒闭并不影响员工的存在

1
2
3
4
5
6
7
8
9

public class Company {
private List<Employee> employees;
}

public class Employee {
private String name;
}

组合

组合表示类之间的整体与部分之间的关系,但它是一种更为强烈的聚合关系

整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不复存在。部分对象不能脱离整体对象而单独存在,就像头和嘴的关系

1
2
3
4
5
6
7
8
9
10
11
public class head {
private final Mouth mouth=new Mouth();

}

public class Mouth {
public void eat(){

}
}

依赖

在代码中,某个类的方法通过局部变量,方法的参数或者对静态方法的调用来访问另一类中的某些方法来完成一些职责

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class Driver{

public final void driver(Car car) {
car.move();
} //当调用driver方法时,必定会使用形参car类对象

}


public abstract class Car{
public void move(){

}
}

继承

在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待

​ 定义父类的格式

1
2
3
4
5
6
7
public class 父类名称{



}


​ 定义子类的格式

1
2
3
4
5
public class 子类名称 extends 父类名称{



}

注:子类在引用时可以找到父类中的方法和变量,但是父类就只能调用自己的

super****详解:

1. super是Java的关键字,他是直接父类对象的引用

​ *2.就像this不能出现在static修饰的方法中一样,super也不能出现在static*修饰的方法中

​ **3.***如果子类定义里父类同名的属性,也会发生子类属性覆盖父类属性的情形。子类的方法直接访问该属性,都会访问到覆盖属性,无法访问父类被覆盖的属性—通过super访问父类被覆盖的属性*

​ *4.如果没有在子类中写super,系统将会自动调用*

​ *5.一般把super写到方法的最前面*

在继承中,当父类有构造方法时,子类一定会调用父类的构造方法

实现

​ \1) 不能直接new抽象类对象,必须用一个子类来继承抽象父类

​ \2) 子类必须覆盖重写抽象父类的所有的抽象方法

​ 重写和覆盖的实现:子类去掉抽象方法的abstract关键字,然后补上方法的大括号

​ \3) 创建子类对象进行使用

​ \4) 在抽象类中,不一定包含抽象对象,但是有抽象方法的类必须是抽象类

软件设计原则

在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据六条原则来开发程序,从而提高软件开发效率、节约软件开发和维护成本

开闭原则

对扩展开放,对修改关闭。在程序需要进行扩展的时候,不能去修改原有的代码。实现一个热插拔的效果,简而言之,是为了是程序的扩展性好,易于维护和升级

想要达到这样的效果,我们需要使用接口和抽象类。

因为抽象类灵活性好,适应性广,只要抽象的合理,可以基本保证软件架构的稳定。而软件中容易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要根据需求重新派生一个实现类来扩展就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public abstract class AbstractSkin {
// 输入法样式
abstract void display();
}


public class Default extends AbstractSkin{
@Override
void display() {
System.out.println("这是默认皮肤");
}
}


public class User extends AbstractSkin{
@Override
void display() {
System.out.println("这是用户自定义皮肤");
}
}


public class SougouInput {
// 创建抽象类对象
public AbstractSkin skin;

public void setSkin(AbstractSkin skin) {
this.skin = skin;
}

public void skien(AbstractSkin skin){
this.skin=skin;
}
public void display(){
skin.display();
}
}


public class run {
public static void main(String[] args) {
// 1.创建搜狗输入法
SougouInput sgi=new SougouInput();
// 2.创建皮肤对象
Default def=new Default();
// 3.将皮肤传入输入法
sgi.setSkin(def);
// 4.展示皮肤
sgi.display();
}
}

里氏原则

子类可以扩展父类的功能,但不能改变父类原有的功能。即子类继承父类时,除添加新增功能外尽量不要重写父类方法

例子:正方形不是长方形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class changfangxing {
private double length;
private double width;

public double getLength() {
return length;
}

public void setLength(double length) {
this.length = length;
}

public double getWidth() {
return width;
}

public void setWidth(double width) {
this.width = width;
}
}


public class zhengfangxing extends changfangxing{
public void setLength(double length){
super.setLength(length);
super.setWidth(length);
}
public void setWidth(double width){
super.setWidth(width);
super.setLength(width);
}
}


public class RectangleDome {
public static void main(String[] args) {
changfangxing cfx=new changfangxing();
cfx.setWidth(10);
cfx.setLength(20);
// 通过resize方法进行扩展
resize(cfx);
print(cfx);

System.out.println("=============");

zhengfangxing zfx=new zhengfangxing();
zfx.setLength(10);
resize(zfx); //会报错
print(zfx);
}
public static void resize(changfangxing changfangxing){ //可以通过多态让正方形方法使用
while (changfangxing.getWidth()<=changfangxing.getLength()){
changfangxing.setWidth(changfangxing.getLength()+1);
}
}
public static void print(changfangxing changfangxing){
System.out.println(changfangxing.getLength());
System.out.println(changfangxing.getWidth());
}
}

更新后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public interface Quadrilateral {
//获取长
double getlength();
//获取宽
double getwidth();
}


public class zhengfangxing implements Quadrilateral{
private double side;

public double getSide() {
return side;
}

public void setSide(double side) {
this.side = side;
}

@Override
public double getlength() {
return 0;
}

@Override
public double getwidth() {
return 0;
}
}


public class changfangxing implements Quadrilateral{
private double width;
private double length;

public void setWidth(double width) {
this.width = width;
}

public void setLength(double length) {
this.length = length;
}

@Override
public double getlength() {
return length;
}

@Override
public double getwidth() {
return width;
}
}

public class RectangleDemo {
public static void main(String[] args) {
changfangxing changfangxing=new changfangxing();
changfangxing.setLength(20);
changfangxing.setWidth(10);
resize(changfangxing);
print(changfangxing);
}
// 扩宽方法
public static void resize(changfangxing changfangxing){ //因为没有继承关系所有正方形无法使用完美解决卡死问题
while (changfangxing.getwidth()<=changfangxing.getlength()){
changfangxing.setWidth(changfangxing.getwidth()+1);
}
}
public static void print(Quadrilateral quadrilateral){
System.out.println(quadrilateral.getlength());
System.out.println(quadrilateral.getwidth());
}
}

倒转依赖原则

​ 要对抽象进行编程不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

​ 例如:组装一台主机,要求有CPU、内存条、硬盘。而CPU有英特尔、AMD等,硬盘可以有希捷、西数,内存条可以选择金士顿和海盗船

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class XijieDisk {
public void save(String data){
System.out.println("使用希捷硬盘存储数据为"+data);

}

public String get(){
System.out.println("使用希捷硬盘取数据");
return "数据";
}

}


public class InterCPU {
public void run(){
System.out.println("使用因特尔处理器");
}
}


public class KingSton {
public void save(){
System.out.println("使用金士顿内存条");
}
}


public class Computer {
private XijieDisk xijie;
private InterCPU inter;
private KingSton kingSton;

public XijieDisk getXijie() {
return xijie;
}

public void setXijie(XijieDisk xijie) {
this.xijie = xijie;
}

public InterCPU getInter() {
return inter;
}

public void setInter(InterCPU inter) {
this.inter = inter;
}

public KingSton getKingSton() {
return kingSton;
}

public void setKingSton(KingSton kingSton) {
this.kingSton = kingSton;
}

public void run(){
System.out.println("运行计算机");
String data=xijie.get();
System.out.println("从硬盘上获取的数据是"+data);
inter.run();
kingSton.save();
}
}


public class run {
public static void main(String[] args) {
XijieDisk xijie=new XijieDisk();
InterCPU inter=new InterCPU();
KingSton kingSton=new KingSton();

Computer c=new Computer();
c.setInter(inter);
c.setXijie(xijie);
c.setKingSton(kingSton);
c.run();
}
}
Other Articles
cover
Vue框架
  • 23/02/27
  • 18:46
  • 9k
  • 46