单例模式
概念:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
UML中带==下划线的属性==是静态的;
如下特点:
- 构造方法私有
- 指向自己实例的私有静态引用
- 以自己实例为返回值的公有静态方法
单例模式可详细分为两类, 饿单例模式,懒单例模式
/**
* 饿汉式单例模式,在类被加载的时候就实例化好了对象
*/
public class SingleTon {
public static SingleTon singleTon = new SingleTon();
private SingleTon() {
}
public static SingleTon getSingleTon() {
return singleTon;
}
}
/**
* 懒汉式单例模式,在调用实例化方法的时候才会创建它的实例
*/
public class SingleTon {
public static SingleTon singleTon;
private SingleTon() {
}
public static synchronized SingleTon getSingleTon() {
if (singleTon == null) {
singleTon = new SingleTon();
}
return singleTon;
}
}
单例模式的优点:
- 在内存中只有一个对象,节省内存空间
- 避免频繁的创建销毁对象,加快效率
- 避免对共享资源的多重占用
- 可以全局访问
适用场景: - 只能适用单例类提供的方法来获取单例对象,使用反射会创建新的对象
- 多线程使用单例模式时,要注意线程安全
- 不要做断开单例类对象与类中静态引用的危险操作。(╯°Д°)╯︵┻━┻
在java中饿汉要优于懒汉,还要因为构造方法是私有的,所以不能被继承ε(┬┬﹏┬┬)3
工厂方法模式
概念:定义一个创建对象的接口,让子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到了子类。
interface IProduct {
public void productMethod();
}
class Product implements IProduct {
@Override
public void productMethod() {
System.out.println("产品");
}
}
interface IFactory {
public IProduct createProduct();
}
class Factory implements IFactory {
@Override
public IProduct createProduct() {
return new Product();
}
}
public class FactoryClient {
public static void main(String[] arg) {
IFactory factory = new Factory();
IProduct product = factory.createProduct();
product.productMethod();
}
}
工厂模式根据抽象程度分为三种:简单工厂模式(静态工厂模式),工厂方法模式,抽象工厂模式。
主要优点:
- 使代码结构清晰,有效的封装变化。在编程中有些产品的实例化是比较复杂的多变的,通过工厂模式,将产品的实例化过程封装起来,使用者不用管产品的实例化过程,只需要依赖工厂即可得到产品对象。
- 调用者屏蔽了具体的产品类,即使产品的实现发生了变化,调用只关心或者依赖产品的接口就好了,不会产生任何影响。
- 降低耦合度,产品的实例化通常是比较复杂的,需要依赖很多的类,而这些类对于调用者来说无需知道,工厂只是把最终的产品对象,交给调用者,产品所依赖的类都是不存在的ヾ(๑╹◡╹)ノ"
通过工厂方法模式的类图可以看出,工厂模式有四个要素:
- 工厂接口,是工厂方法模式的核心,用于与调用者交互,用来提供产品。
- 工厂实现,决定如何实现产品,有多少种产品,就要有多少种工厂实现。
- 产品接口,所有产品都必须遵守产品接口所定义的规范,产品接口也是调用者最关心的,产品接口定义的好坏,决定了代码的稳定性,与工厂接口一样,可以用抽象类来代替,但是不能违反里氏替换原则ヽ(#`Д´)ノ┌┛〃
- 产品实现,决定了产品的在客户端的具体行为。
适用场景:
作为“创建类模式”,在任何需要生成复杂对象的地方,都可以使用工厂模式。
如果创建一个类需要大量的依赖其他类,那么调用者就会产生很强的耦合度,这时候可以考虑使用工厂模式,来降低调用者与外界的耦合度。
建造者模式
定义:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
类型:创建类模式
四个要素:
- 产品类,一般是一个创建过程较为复杂的对象,在实际编程中,产品类可以是一个抽象类,或多个抽象类及其实现子类组成;
- 抽象建造者,为了将具体的建造过程交于他的子类实现,更容易扩展,最少有两个方法,一个是建造产品,一个是返回产品。
- 建造者,实现抽象建造者的方法,组建产品,返回组建好的产品。
- 导演类,调用适当的建造者来组建产品,一般不与产品发生依赖,用于封装程序中易变的部分(メ`ロ´)/
class Product {
private String name;
private String type;
public void setName(String name) {
this.name = name;
}
public void setType(String type) {
this.type = type;
}
public void showProduct() {
System.out.println("name = " + name);
System.out.println("type = " + type);
}
}
abstract class Builder {
public abstract void setPart(String arg1, String arg2);
public abstract Product getProduct();
}
class ConcreteBuilder extends Builder {
private Product product = new Product();
@Override
public void setPart(String arg1, String arg2) {
product.setName(arg1);
product.setType(arg2);
}
@Override
public Product getProduct() {
return product;
}
}
/**
* 导演让你创建啥,你就创建啥ヾ(o・ω・)ノ
*/
class Director {
private Builder builder = new ConcreteBuilder();
public Product getAProduct() {
builder.setPart("保时捷", "卡宴");
return builder.getProduct();
}
public Product getBProduct() {
builder.setPart("凤凰牌", "自行车");
return builder.getProduct();
}
}
public class BuilderClient {
public static void main(String[] args) {
Director director = new Director();
Product p1 = director.getAProduct();
p1.showProduct();
Product p2 = director.getBProduct();
p2.showProduct();
}
}
建造者模式的优点:
- 一般产品类和建造者类都是比价稳定的,因此,将主要逻辑,以及具体实现,这些易变的部分封装在了导演类中。
- 当有现需求时候,只要实现一个新的建造者类就可以不动之前经过测试的代码了,不会引入风险。
建造者模式与工厂模式的区别:
与工厂模式相比,建造模式一般用来创建更加复杂的对象, 因为更加复杂的对象创建过程,需要一个导演类将这个复杂的创建过程独立出来。也就是说工厂模式将所有的对象创建过程封装在工厂中,有工厂类想客户端提供最终的产品。而建造者模式中,建造者只提供产品的各个组件的建造,然后将具体的建造过程交给导演类,由导演类将各个组件的建造特定的规则组成产品,交给客户端。
原型模式(Prototype)
定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
类型:创建类模式
原型模式主要用于对象的复制,它的核心就是原型类prototype,prototype需要具备两个条件
- 实现Cloneable接口,它的作用只有一个,就是通知虚拟机可以安全的在实现了此接口的类上使用clone方法。只有实现了这个接口的类才可以被clone。
- 重写clone方法,将权限修饰符修改为public,
模板方法模式(template)
定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中去,使子类可以不改变算法的结构,即可重新定义某些特性的步骤.
架构师将整个应用的大体逻辑,试用大量的接口或者抽象类讲真个系统串起来,然后根据实现的难度不同交给高级工程师,初级工程师,由他们来实现子类,完成开发。
模板方法模式的结构:
模板方法模式由一个抽象类和一组(n>=1)子类组成,抽象类中方法分为三种
- 抽象方法,父类只声明而不实现,定义好规范,然后由其子类去实现。
- 模板方法,由抽象类声明并加以实现,一般来说模板方法调用抽象方法来完成主要的逻辑功能,并且,模板方法大多数会定义成final类型,指明主要的逻辑在子类中无法被重写。
- 钩子方法,由抽象类声明并加以实现,但是子类可以去扩展,子类可以通过扩展钩子方法,来影响模板方法的逻辑。
- 抽象类的任务是搭建逻辑框架,通常由经验丰富的人,抽象类的好坏直接决定了程序是否稳定,
- 实现类用来实现细节,模板方法正式通过实现类中扩展的方法来完成逻辑,只要实现类中扩展方法通过了单元测试,在模板方法正确的前提下,一般整体不会出现太大的错误。
适用场景:
- 容易扩展,一般来说,抽象类中的模板方法是不易发生改变的部分,而抽象方法式容易发生改变的部分,因此通过增加实现类一般很容易实现功能的扩展,符合开闭原则。
- 便于维护,对于模板方法模式来说,正是由于他们的主要逻辑相同,才使用模板方法。
- 灵活,因为有钩子方法,因此子类的实现也可以影响父类的主要运行逻辑,但是却违反了里氏替换原则。
- 多个子类拥有相同的方法,并且这些方法的逻辑相同的情况下可以使用模板方法模式,在程序的主框架相同,细节不同的情况下,比较适合使用这种模式。
中介者模式
定义:用一个中介者对象封装一些列的交互对象,中介者使个对象不需要显示的互相作用,从而降低耦合,而且可以独立的改变他们之间的交互。
结构:中介者模式又称为调停者模式,氛围三部分
- 抽象中介者,定义好同事类对象到中介者对象的接口,用于各同事类之间的通讯,一般包括一个或者多个抽象的时间方法,并由子类去实现。
- 中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
- 如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。
代理模式
为其他对象提供一种代理以控制这个对象的访问。
结构:
- Subject抽象主题角色,可以是抽象类也可以是一个接口,普通业务类型的定义,无特殊要求。
- RealSubject具体角色,被委托角色,业务逻辑具体执行者。
- Proxy代理角色,负责对真实角色的应用,把所有抽象主题的方法,委托给真是主题角色实现,并且在真实角色处理完毕前后座预处理和善后工作。
模板代码:
interface Subject {
void request();
}
class RealSubject implements Subject {
private String name;
public RealSubject(String name) {
this.name = name;
}
@Override
public void request() {
System.out.println("name = " + name);
}
}
class Proxy implements Subject {
private Subject subject = null;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
this.before();
this.subject.request();
this.after();
}
//预处理工作
private void before() {
System.out.println(System.currentTimeMillis() + "预处理工作");
}
//善后工作
private void after() {
System.out.println(System.currentTimeMillis() + "善后工作");
}
}
public class ClientProxy {
public static void main(String[] args) {
Subject subject = new RealSubject("zhangsan");
Subject proxy = new Proxy(subject);
proxy.request();
}
}
1506480477076预处理工作
name = zhangsan
1506480477076善后工作
代理模式优点:
- 职责清晰,真是角色就是实现实际的业务逻辑,不用关心其他非本职事物,
- 高扩展性,具体主题角色可以随时改变,只要实现了接口,甭管怎么变化,都逃不出我的手心,代理类可以不改变的情况下使用。
- 智能化,︵╰(‵□′)╯︵┻━┻
观察者模式
定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象,都会的到通知并自动更新。
在软件系统中通常会有这样的需求,如果一个对象的状态发生改变,某些与他先关的对象也要做出改变。
结构:
- 被观察者,从类图中可以看到,类中有一个用来存放观察者对象的Vector的容器,(在多线程中Vector是线程安全的,而不是用list),这个集合是被观察者的核心,另外有三个方法,attach方法,向这个容器中添加观察者对象,detach方法,从容器中移除观察者对象,notify方法,依次调用观察对象的对应方法。这个角色可以是是接口,也可以是抽象类或者具体的类,因为很多情况是和其他模式一起使用。
- 观察者,观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生改变是,这个方法就会被触发调用。
- 具体的被观察者,使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑。
- 具体的观察者,定义被观察者状态发生改变时,回调的观察者对象具体处理的逻辑。
/**
* 被观察者
*/
abstract class Observeable {
private Vector<Observer> vector = new Vector();
public void addObserve(Observer obs) {
this.vector.add(obs);
}
public void removeObserve(Observer obs) {
this.vector.remove(obs);
}
protected void notifyObserve() {
for (Observer observer : vector) {
observer.update();
}
}
public abstract void doSomething();
}
/**
* 被观察者实例
*/
class ContractObserve extends Observeable {
@Override
public void doSomething() {
System.out.println("被观察者事件发生");
this.notifyObserve();
}
}
interface Observer {
void update();
}
/**
* 实例观察者1
*/
class ConcreteObserve1 implements Observer {
@Override
public void update() {
System.out.println("观察者1收到信息,并进行处理");
}
}
/**
* 实例观察者2
*/
class ConcreteObserve2 implements Observer {
@Override
public void update() {
System.out.println("观察者2收到信息,并进行处理");
}
}
public class ObserveClient {
public static void main(String[] args) {
//创建被观察者
//这里真正new的都是实现子类
Observeable obs = new ContractObserve();
obs.addObserve(new ConcreteObserve1());
obs.addObserve(new ConcreteObserve2());
obs.doSomething();
}
}
观察者模式的优点:
观察者与被观察者之间是一种轻度的关联关系,并且是抽象耦合的,这样对于二者来说都比较容易扩展。观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理,但同时由于是链式触发,所以当观察者较多的时候,性能是比较担忧的,
责任链模式
定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,将这些对象连成一条线,并沿着这条线传递这些请求,知道有对象处理请求为止。
策略模式
定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以相互转换。
策略模式是把算法封装到一系列的类中去,并且这些类实现相同的接口,相互之间可以相互替换。他与模板方法的区别在于,在模板方法模式中调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是在封装了Context的封装类中。
结构:
- 封装类,也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
- 抽象策略,通常情况下为一个接口,当各个类中出现重复的逻辑时候,使用抽象类来封装这部分代码,此时会看上去像是模板方法。
- 具体策略,具体策略通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。
策略模式的优点
- 策略类之间可以相互转换,由于策略类实现自统一个抽象,所以他们之间可以自由切换。
- 易于扩展,增加一个新的策略模式非常的简单,可以在不修改原有代码的基础上进行扩展。
- 避免使用多重条件,如果不使用策略模式,所有的算法需要用条件语句去进行连接,这样的做法非常不容易维护。
- 维护各个策略类给开发者带来额外的开销。
- 客户端必须要知道所有策略类的区别,然后决定用哪一个,但是有违背迪米特法则。
ヽ(`Д´)ノ︵ ┻━┻
适用场景:
策略模式实际上就是面向对象中的继承和多态。
- 几个类的主要逻辑相同,只是部分逻辑和算法上有所区别的情况。
- 有相似的行为,或者算法,客户端需要动态的取决定使用哪一个,那么可以使用策略模式,将这些算法封装起来供客户端调用。
- 一般与工厂方法模式,模板方法模式混合使用情况较多。
网友评论