设计模式
1、单例(Singleton):确保一个类只有一个实例,并提供该实例的全局访问点。
使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。 私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。 1)懒汉式-线程不安全 保证线程安全的方式:①加锁(只在创建实例的时候加锁,所以双重判断);
②静态内部类,由于static final修饰为常量,存储在方法区,因此可以同时保证延迟创建和线程安全;
③枚举实现,可以防止反射攻击; 2)饿汉式-线程安全:直接实例化的方式也丢失了延迟实例化带来的节约资源的好处
2、简单工厂(Simple Factory):在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口
//简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。 public class SimpleFactory { public Product createProduct(int type) { if (type == 1) { return new ConcreteProduct1(); } else if (type == 2) { return new ConcreteProduct2(); } return new ConcreteProduct(); } } public class Client { public static void main(String[] args) { SimpleFactory simpleFactory = new SimpleFactory(); Product product = simpleFactory.createProduct(1); // do something with the product } }
3、工厂方法(Factory Mrthod):定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
//在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。 //Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现 public abstract class Factory { abstract public Product factoryMethod(); public void doSomething() { Product product = factoryMethod(); // do something with the product } } public class ConcreteFactory extends Factory { public Product factoryMethod() { return new ConcreteProduct(); } } public class ConcreteFactory1 extends Factory { public Product factoryMethod() { return new ConcreteProduct1(); } } public class ConcreteFactory2 extends Factory { public Product factoryMethod() { return new ConcreteProduct2(); } }
4、抽象工厂(Abstract Factory):提供一个接口,用于创建 相关的对象家族
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。 抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。 至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。 public class AbstractProductA { } public class AbstractProductB { } public class ProductA1 extends AbstractProductA { } public class ProductA2 extends AbstractProductA { } public class ProductB1 extends AbstractProductB { } public class ProductB2 extends AbstractProductB { } public abstract class AbstractFactory { abstract AbstractProductA createProductA(); abstract AbstractProductB createProductB(); } public class ConcreteFactory1 extends AbstractFactory { AbstractProductA createProductA() { return new ProductA1(); } AbstractProductB createProductB() { return new ProductB1(); } } public class ConcreteFactory2 extends AbstractFactory { AbstractProductA createProductA() { return new ProductA2(); } AbstractProductB createProductB() { return new ProductB2(); } } public class Client { public static void main(String[] args) { AbstractFactory abstractFactory = new ConcreteFactory1(); AbstractProductA productA = abstractFactory.createProductA(); AbstractProductB productB = abstractFactory.createProductB(); // do something with productA and productB } }
5、生成器(Builder):封装一个对象的构造过程,并允许按步骤构造。
Builder模式主要用于“分步骤构建一个复杂对象”。在这其中“分步骤”是一个稳定算法,而复杂对象的各个部分则经常变化。
6、原型模式(Prototype):使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象。
Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。 1)由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。 2)目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。 3)根据对象克隆深度层次的不同,有浅度克隆与深度克隆。
适用情况: 一个复杂对象,具有自我复制功能,统一一套接口。 对于对象比较复杂,每创建一次new 都会浪费好多的资源和时间 且在初始化的信息不发生变化的前提下 克隆是最好的办法,
public abstract class Prototype { abstract Prototype myClone(); } public class ConcretePrototype extends Prototype { private String filed; public ConcretePrototype(String filed) { this.filed = filed; } @Override Prototype myClone() { return new ConcretePrototype(filed); } @Override public String toString() { return filed; } } public class Client { public static void main(String[] args) { Prototype prototype = new ConcretePrototype("abc"); Prototype clone = prototype.myClone(); System.out.println(clone.toString()); } }
7、责任链(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
8、命令(Command):将命令封装成对象中,具有以下作用:
- 使用命令来参数化其它对象
- 将命令放入队列中进行排队
- 将命令的操作记录到日志中
- 支持可撤销的操作
Command:命令
Receiver:命令接收者,也就是命令真正的执行者
Invoker:通过它来调用命令
Client:可以设置命令与命令的接收者
9、解释器(Interpreter):为语言创建解释器,通常由语言的语法和语法分析来定义.
10、迭代器(Iterator):提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
Iterator 主要定义了 hasNext() 和 next() 方法。
11、中介者(Mediator):集中相关对象之间复杂的沟通和控制方式。
12、备忘录(Memento):在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
13、观察者(Observer):定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
14、状态(State):允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
15、策略(Strategy):定义一系列算法,封装每个算法,并使它们可以互换。策略模式可以让算法独立于使用它的客户端。
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。
所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
16、模板方法(Template Method):定义算法框架,并将一些步骤的实现延迟到子类。通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
17、访问者(Vister):为一个对象结构(比如组合结构)增加新能力。
18、空对象(Null):使用什么都不做的空对象来代替 NULL。一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。
19、适配器(Adaptor):把一个类接口转换成另一个用户需要的接口。
20、桥接(Bridge):将抽象与实现分离开来,使它们可以独立变化。
Abstraction:定义抽象类的接口
Implementor:定义实现类接口
21、组合(Composite):将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。
组件(Component)类是组合类(Composite)和叶子类(Leaf)的父类,可以把组合类看成是树的中间节点。
组合对象拥有一个或者多个组件对象,因此组合对象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。
22、装饰(Decorator):为对象动态添加功能。
装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。
类应该对扩展开放,对修改关闭:也就是添加新功能时不需要修改代码。
23、外观(Facade):提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。