这是我参与8月更文挑战的第3天,活动详情查看: 8月更文挑战
效果图
什么是设计模式
什么是设计模式?设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计程序精英们的经验总结
为什么使用设计模式?使用设计模式是为了可重用代码(不修改或者少修改代码来解决新的问题),减少重复工作、让代码更容易被他人理解、保证代码可靠性。
设计模式是编程过程中的一种中间层面的技巧或者经验(微观层面的如算法、数据结构、语法,宏观层面的如框架、工具箱、系统架构),是许多优秀的程序员通过大量实际项目的磨练所总结出来的 “内功秘籍”, 通过学习他们的高效的方法、总结出经验技巧,那么在我们遇到一个具体问题时,也更加容易想到优秀合理的解决方案。
什么是单例模式(Singleton)
什么是单例模式(Singleton),简而言之,在程序运行期间,单例类的实例只能有一个(或没有)。单例模式是一个非常实用的设计模式,一般会用在管理类或者程序里只有唯一实例的类。打个比方,一个公司的管理者 CEO,就可视作单例。再举一个实际的例子,比如游戏里的资源管理类,我们可能需要随时访问它,但不希望每次加载图片的时候都要从新创建一个资源管理类的实例(避免频繁创建销毁对性能所带来的影响),那么单例模式就是一个很好的解决方案。
Processing 不同于 Java 的实现
和直接使用 Java 实现单例模式不同,Processing 有其特别之处,特别需要注意:
在 PDE 中声明的默认类是内部类,不能有静态字段。要实现单例模式,你需要创建一个顶级类(top-level),为了达到这个目的,我们首先添加一个新标签,当被要求命名它时,切记选项卡的名称这里很重要!!!类的名称后面必须跟着 '.java',例如使用 SimpleImageManager.java
在 SimpleImageManager.java 选项卡中添加以下代码
import processing.core.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class SimpleImageManager {
private static PApplet app;
private static SimpleImageManager instance; /// < 私有的实例,无法直接访问
private ArrayList<PImage> imgs = new ArrayList<PImage>();
/// @note 私有的构造函数,无法直接访问
private SimpleImageManager() {
}
/// @note 开放的部分【暂不考虑多线程访问的情况】
public static SimpleImageManager getInstance(PApplet papp) {
/// @note 如果尚未初始化,则创建一个实例
if (instance == null) {
instance = new SimpleImageManager();
app = papp;
}
/// @note 直接返回已创建的实例
return instance;
}
public void draw() {
/// @note 将图片横向排列
for (int i = 0; i < imgs.size(); i++) {
app.image(imgs.get(i), i * 171, 0);
}
}
/// @note 加载指定文件夹下的图片
public void loadImages(String path) {
File dir = new File(path);
if (dir.exists() && dir.isDirectory()) {
System.out.println("目录存在!");
File[] files = dir.listFiles();
for (File f : files) {
String filepath = path + f.getName();
// System.out.println(filepath); ///< 测试
PImage img;
img = app.loadImage(filepath);
img.resize(171, 256); /// < 对每张图进行缩放
imgs.add(img);
}
} else {
System.out.println("目录不存在!");
}
}
}
主调用 pde 的代码为
这里的调用也十分简单,就是做了一个 实例变量是否相同的判断 以及 绘制
SimpleImageManager inst, inst_;
void setup() {
size(1200, 256);
background(255);
/// @note 首次创建实例
inst = SimpleImageManager.getInstance(this);
inst.loadImages("/Users/lingyunpan/Documents/Processing/projects/Images/"); ///< Mac 下的目录
/// @note 模拟再次获取实例
inst_ = SimpleImageManager.getInstance(this);
/// @test
if(inst == inst_){
println("inst 和 inst_ 是同一个实例变量。");
}
/// @note 使用 inst_ 来绘制,不用重复加载图片
inst_.draw(); ///< 由于窗口大小限制,最多显示 7 张
}
最终的效果,如文章开头所示。
设计模式可分为三类
1.创建型:提供对象创建机制,增加现有代码的灵活性和重用。
- 单例模型
- 原型模式
- 工厂方法模式
- 抽象工厂模式
- 建造者模式
2.结构型:解释如何将对象和类组装成更大的结构,同时保持结构的灵活性和高效性
- 适配器模式
- 桥接模式
- 装饰模式
- 外观模式
- 代理模式
- 享元模式
- 组合模式
3.行为型:负责有效的沟通和对象之间的责任分配。
- 模板方法模式
- 策略模式
- 命令模式
- 职责链模式
- 状态模式
- 观察者模式
- 中介者模式
- 迭代器模式
- 访问者模式
- 备忘录模式
- 解释器模式
最后附上 面向对象 的 7 大原则的精辟总结
1、单一职责原则(Single Responsibility Principle, SRP)
当需要修改某个类的时候原因有且只有一个。换句话说就是让一个类只做一种类型责任,当这个类需要承担其他类型的责任的时候,就需要分解这个类。
例:你不能要求一个程序员既会写程序又会招聘,如果你需要招聘新员工的时候,还是专门找一个HR或者猎头比较好。
2、开闭原则 (Open-Closed Principle, OCP)
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
例:有程序员这么一个类型的职业,你可以派生出C++程序员、Java程序员、C#程序员、会PS的C#程序员、不喜欢写注释的程序员,这就是开原则。但你不能要求所有的程序员都会C++、会Java、会C#、会PS且会C#、不喜欢写注释,这就是闭原则。
3、依赖倒转原则(Dependence Inversion Principle, DIP)
高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
例:公司高层不应该依赖于低层的程序员,想开掉就开掉,大不了再招一个(苦逼的程序员要重新找工作了……)。程序员这个职业不应该依赖于某个特定的编程语言,而会了某一种编程语言,你就可以称为程序员了。
4、接口隔离原则(Interface Segregation Principle, ISP)
不能强迫用户去依赖那些他们不使用的接口。换句话说,使用多个专门的接口比使用单一的总接口总要好。
例:讨论UI的时候还是不要叫上服务器程序员了。
5、里氏替换原则 (Liskov Substitution Principle, LSP)
任何基类可以出现的地方,子类一定可以出现。
例:员工上下班都需要打卡,那么程序员上下班也需要打卡,如果你看到一个人上下班没有打卡,那可能是老板。
6、组合/聚合复用原则 (Composite Reuse Principle, CRP)
要尽量使用合成/聚合,尽量不要使用继承。
例:组建一个新团队的时候,如果先把老团队的人全部拉过来再按照需要招人的话,可能并不是所有人都有事情做。
7、最小知识原则 (Law of Demeter, LoD)
就是说一个对象应当对其他对象有尽可能少的了解。
例:作为一个策划(或者PM),不需要了解程序是怎么实现的,只要提需求就行了。“上联:这个需求很简单,下联:怎么实现我不管,横批:明天上线。”