Java有很多种模式,以下的是一些总结的模式。
(1) 单例模式 (实现方式 私有构造器 + 私有静态本身的实例 + 共有实例方法返回本身的实例), 需要判断是否已经生成过实例)一个类只允许其有一个实例化对象 在并发程序中用的可能比较多, 涉及线程安全, 我自己知道的是Spring 依赖注入, 在容器中的Bean一般都是单例的..
public class Singelton { // 最平凡的实现方式
private volatile static Singelton singelton;
public static Singelton getInstance(){
if(singelton == null) {
synchronized {
if(singelton == null) {
singelton = new Singelton();
return singelton;
}
}
}
}
}
单例模式的三种实现方式:
饿汉方式:
对象类型声明成static final 类型, 并且直接实例化 然后用getInstance()方法来获取变量引用 这样可以保证对象唯一
懒汉方式:
对象类型声明成 volatile static 类型
通过getInstance 的判断 来实现对象唯一, 但是这个要考虑到并发问题, 多线程情况下并不安全, 需要用双重检查机制, 并且把类型声明称volatile static
最好的方式(java语言 也就是因为jvm才特有的方法):
通过内部私有静态类来实现单例, 在这个类内部实例化一个static final的实例
然后用一个方法调用这个静态类的这个静态实例 他的优点就是结合了上头两种方式的所有优点, 即可以懒加载, 也可以保护线程安全,
(2)工厂模式(一个创建型设计模式) 有很多实现的例子 比如说很多带有*BeanFactrory的类 都是工厂模式的体现 他通过形参等 生成不同的对象 LoggerFactory BeanFactory 等. 其实就是通过工厂的方式, 返回某个接口不同的实例, 其实就是可以根据客户要求的返回她想要的产品..
工厂模式分为三种:
第一种: 简单工厂(静态工厂) 有一个工厂类拥有一个静态的方法, 用来产生产品实例, 通过传递参数的不同来区分生成哪个产品实例.
第二种: 工厂方法 : 这个是用来解决简单工厂存在的问题 比如: 增加一个产品简单工厂需要对工厂类代码进行修改, 增加一个判断条件, 这样就增加了代码的复杂程度, 工厂方法为了解决这个问题, 通过多态的方式来实现不同的工厂类来生产不同的产品. 即会有一个工厂接口, 通过实现工厂接口的方式实现新的工厂类, 来代替修改工厂类代码, 这样会使得代码耦合度降低.
(更深一步, 工厂类甚至可以加入产品的业务方法, 直接调用本身创建的产品的方法).
第三种: 抽象工厂 为产品分类, 将纵向的产品实现类, 横向化, 就是组成更大的产品工厂 具体实现如图:(手画工厂图) 用来生产复杂的产品.
(3)观察者模式 用于一对多 或者是 一对一 关系中 在一中有什么改动 会导致和他有关系的多(也就是观察者们也发生变动)
Redis 实现异步消息队列 有一种实现方式叫: 发布订阅者模式 类似但是 调度方式不一样 观察者模式由发布者调度 而 另一种模式不是 他有单独的调度中心
例子:
public interface Subject {
public void attach(Observer o);
public void detach(Observer o);
public void notice();
}
interface Observer{
public void update();
}
class Student implements Observer{
String teacherPhone = "";
Teacher teacher ;
public Student(String phone,Teacher t){
teacher = t;
teacherPhone = phone;
}
@Override
public void update() {
teacherPhone = teacher.getPhone();
}
public void show(){
System.out.println(teacherPhone);
}
}
class Teacher implements Subject{
private String phone;
private ArrayList<Observer> students;
public Teacher(){
phone = "";
students = new ArrayList<Observer>();
}
@Override
public void attach(Observer o) {
students.add(o);
}
@Override
public void detach(Observer o) {
students.remove(o);
}
@Override
public void notice() {
for(Observer o:students){
o.update();
}
}
public String getPhone(){
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
notice();
}
}
Test:
public static void main(String[] args) {
Teacher teacher = new Teacher();
Student s = new Student("",teacher);
Student s1 = new Student("",teacher);
teacher.attach(s);
teacher.attach(s1);
teacher.setPhone("13215646");//核心在这个set方法上 他的变动导致很多都发生了改变
s.show();
s1.show();
}
(4) 外观模式(门面模式) Facade Pattern
这个感觉是最简单的 他通过一个门面类 将具体操作隐藏在方法中 客户只需要调用方法 不用知道具体的实现 这样就很好
(说的个更加科学一点就是, 这个模式的作用就是实现客户端和子系统的解耦, 用户在调用客户端接口的时候我们可以将它具体调用的操作隐藏起来, 只需要给他提供一个门面接口, 这样就可以使得调用更加简单)
public void Solution(){
Analyze a = new Analyze();//这三个类的具体实现不知道 不过用户只要对调用方法 自动都会产生结果
Think t = new Think();
Finally f = new Finally();
a.Analyze();
t.Think();
f.Finally();
}
public class Test {
public static void main(String[] args) {
Problem p = new Problem();
p.Solution();
}
}
(5)组合模式 解释一下这个模式是什么, 首先他是用来解决树形对象模型的(这个说的有一点不是很确切, 我感觉组合模式是用来解决类似有多种不同的对象, 但是他们之间还有一定的相似性 类似于这种问题就可以用组合模式来解决, 组合模式可以将他们抽象到一个Component), 就是例如文件系统这种树形的结构. 他的方式是通过将叶子节点(文件), 非叶子结点(文件夹) , 抽象成一个component类或者是接口, 然后叶子节点和非叶子结点, 分别实现一下这个类, 然后通过重写方法的形式来实现树形遍历
还分为两种: 透明组合模式 安全组合模式
(6)命令模式
先上图:(传统的命令模式 可能都不是这么用)
这个模式可以类比于开关, 有不同的功能选项, 当你按不同的按钮的时候, 会有不同的物品反应你的命令(暂时理解就是这个含义)
对于上图来说, 一个命令模式需要一个Invoker调用者, 也就是发出命令的人, 它关联了一个command对象(或者是一系列command对象), 然后我们需要具体的command实现类, 用来调用Handler(某个功能具体的实现类), 这个图还少了个模块就是我们应该将Handler抽象成接口, 这样的话, 如果添加删除具体的Handler也可以减少我们修改之前的代码. 然后我们的逻辑关系是, 我们的实现类接口会关联一个Handler, 通过set方法set具体的Handler实现类之后, 调用具体的功能模块.................(这是传统的)
但是现在的命令名模式很多情况下都不是直接将Handler和Command 耦合起来, 因为我们要满足设计的高内聚弱耦合的原则, 所以 -> 演变出了一个命令队列.
(7)装饰模式 (分为透明装饰模式和半透明装饰模式)
然后简单的说一下这个模式是什么, 这个模式是为了为被修饰的类添加一个方法, 其实就是装饰一下一个类, 使其具有其他功能, 具体的实现方式是: 首先我们需要一个被装饰的抽象构建Component(其有一个需要被修饰的方法), 然后我们需要一个抽象装饰器类Decorator, 实现我们的需要被修饰的抽象构建, 然后与其关联一下. 最后我们需要一个具体的装饰器类ConcreteDecorator, 它实现我们的抽象装饰器类, 然后加入我们要加入的 方法, 这样我们就可以为我们的具体实现类set一个ConcreteComponent, 之后就可以调用被修饰的方法.
(8)代理模式 这个模式较难 单独建立了一个文档 详见 java学习/代理模式
(9)原型模式 这个模式就是获取原型的一个克隆对象, 克隆对象和原型不能是同一个对象的引用. 在java中可以调用基类Object 的clone() 方法, 但是要重写这个方法必须实现Cloneable
这个模式有两种级别:
浅克隆 : 就是上头说到的那种情况, 实现一个Cloneable 接口 这个只能克隆基本类型, 但是对于引用类型 他只能克隆引用类型的地址 所以说引用类型的对象克隆之后两个实例指向的还是一个对象
深克隆 : 这个是通过实现一个Serializable 接口来实现 , 把对象实例放到流里, 然后再取回来, 这样就可以获得一个新的克隆实例
(10)建造者模式
建造者模式类似于抽象工厂模式, 抽象工厂是将不同的产品进行组合, 组合成新产品, 他是用来生产复杂产品(也就是类)的. 类似的, 建造者模式是用来产生复杂对象的, 在这里两者的核心区别就是, 建造者模式使用来生产复杂对象的, 他把一个对象的不同属性的建造抽象化, 也就是说一个对象的属性的值是通过调用建造函数获取的, 相对的抽象工厂是用来讲不同种的产品(也就是类) 组合起来生成新的产品的过程, 他的组装对象是类. 而建造者模式组装的是属性
首先他分为, 要生产的对象 Actor , 建造者(AbstrackBuilder, *Builder) , 控制者
抽象建造者有一个Actor类型的属性, 并且有为这个Actor 的各个属性赋值的函数, 具体建造者继承抽象建造者, 然后实现具体的建造函数, 最后控制者需要一个具体建造者作为参数, 控制者分别调用具体建造者的建造函数, 然后获取这个建造出来的Actor 也就是说我可以选择不调用某个函数, 这样就很灵活
(11)适配器模式
这个模式的含义我的理解是, 我们有一个(目标/目的)抽象类的两个方法, 但是在某个地方已经有实现了的现成的方法, 那么我们想要不用自己再重新实现一遍这两个一样的方法有两种办法 1.把之前实现的代码copy过去, 2. 就是写一个目标抽象类的适配器,
对于第二种方法也就是实现这个抽象类然后提供一下这两个方法的实现, 然后这两个方法的实现是通过关联已经实现过这两个方法的类然后调用他们的方法来实现, 这样就避免了copy代码从而增加代码长度, 而且冗余度高的问题.
然后适配器模式还分为对象适配器模式和类适配器模式, 对象适配器模式是通过关联的方式来调用适配者的方法, 但是类适配器模式是通过继承的方式, 由于java语言单继承的特性, 其实这个类适配器模式很少被使用,
适配器模式有一种双向适配器模式, 这个其实就是可以双向适配. 适配者是双方的.还有一种叫缺省适配器, 缺省适配器的最大的特点就是适配器类是一个抽象的, 他不用实现目标接口的所有方法, 而是可以只实现几个.
(12)桥接模式
废话不多说先来上个图
来解释一下这个桥接模式, 首先他的作用是分离一个实体中两种或者多种维度的抽象, 把他们抽象成抽象类 -> 关联 -> 抽象接口的模式 这样就可以了 要增添新的类型, 只需要在他对应的维度下创建一个对应的具体实现类, 然后就可以实现复杂功能的解耦.
(13) 享元模式 (不是特别常用)
这个模式的作用就是, 实现一个享元工厂, 将一些具有相同功能的对象集中起来, 减少对象的数量, 降低系统因为对象冗余导致的内存消耗, 最典型的例子运用了享元模式的就是String这个对象. 每次创建新对象的时候他总是要先在常量池中查找是不是已经有了相同字符串的引用如果有了的话就不用在创建一个新的对象了, 只要把之前那个字符串的引用返回即可
(14)职责链模式
责任链模式是什么尼? 其实责任链模式就是对于一系列的处理, 请求需要在一个链上依次传递. (类似于jsp的过滤器和Spring的拦截器)
责任链模式分为纯的责任链模式和不纯的责任链模式.
纯的责任链就是责任链的每一个handler只能选择两种处理1: 处理请求 2: 传给下一个
不纯的责任链其实就是handler在处理完之后可以再传给下一家。
当然,还有其他的模式,就不一一阐述了。仅供参考。