一、单列模式:一个类只允许产生一个实例化对象;
Singleton是一个创建型模式,指某个类采用Singleton模式后,则这个类在创建之后,只会可能产生一个实例供外部访问,并且提供一个全局的访问点。
实现方式有懒汉式和饿汉式共四种:
1、饿汉式,线程安全 但效率比较低 :
public class SingletonTest {
private SingletonTest() {
}
private static final SingletonTest instance = new SingletonTest();
public static SingletonTest getInstancei() {
return instance;
}
}
2、懒汉式,非线程安全:
public class SingletonTest {
private SingletonTest() { //私有构造方法
}
private static SingletonTest instance; //声明变量
public static SingletonTest getInstance() { //提供对外方法
if (instance == null)
instance = new SingletonTest();
return instance;
}
}
3、懒汉式,线程安全,但是效率非常低:
public class SingletonTest {
private SingletonTest() { //私有构造方法
}
private static SingletonTest instance; //声明变量
public static synchronized SingletonTest getInstance() { //提供对外方法
if (instance == null)
instance = new SingletonTest();
return instance;
}
}
4、懒汉式,线程安全 并且效率高(常用):
public class SingletonTest{
//声明变量
public static Singleton instance;
//私有构造方法
private SingletonTest(){
}
//提供对外方法
public static SingletonTest getInstance(){
if (instance == null){
synchronized(SingletonTest.class){
if (instance == null){
instance = new SingletonTest();
}
}
}
return instance;
}
}
二、工厂设计模式
工厂方法模式:
- 工厂方法模式分为三种:普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
- 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
- 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
1、普通工厂模式:
建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
interface Sender {
void Send();
}
class MailSender implements Sender {
@Override
public void Send() {
System.out.println("This is mail sender...");
}
}
class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("This is sms sender...");
}
}
public class FactoryPattern {
public static void main(String[] args) {
Sender sender = produce("mail");
sender.Send();
}
public static Sender produce(String str) {
if ("mail".equals(str)) {
return new MailSender();
} else if ("sms".equals(str)) {
return new SmsSender();
} else {
System.out.println("输入错误...");
return null;
}
}
}
2、多个工厂方法模式:
该模式是对普通工厂模式的改进,在普通工厂模式中,如果传递的字符串出错,则不能正确的创建对象,而多个工厂模式是多个工厂方法,分别创建对象。
interface Sender {
void Send();
}
class MailSender implements Sender {
@Override
public void Send() {
System.out.println("This is mail sender...");
}
}
class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("This is sms sender...");
}
}
class SendFactory {
public Sender produceMail() {
return new MailSender();
}
public Sender produceSms() {
return new SmsSender();
}
}
public class FactoryPattern {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produceMail();
sender.Send();
}
}
3、静态工厂方法模式:
将上面的多个工厂方法模式设置为静态的,不需要创建实例,直接调用即可。
interface Sender {
void Send();
}
class MailSender implements Sender {
@Override
public void Send() {
System.out.println("This is mail sender...");
}
}
class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("This is sms sender...");
}
}
class SendFactory {
public static Sender produceMail() {
return new MailSender();
}
public static Sender produceSms() {
return new SmsSender();
}
}
public class FactoryPattern {
public static void main(String[] args) {
Sender sender = SendFactory.produceMail();
sender.Send();
}
}
4、抽象工厂模式:
在工厂方法模式中,类的创建依赖工厂类,如果想扩展应用程序,就必须对工厂类进行修改,这违背了闭包原则,那么久用到了抽象工厂模式,创建多个工厂类,一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
interface Provider {
Sender produce();
}
interface Sender {
void Send();
}
class MailSender implements Sender {
public void Send() {
System.out.println("This is mail sender...");
}
}
class SmsSender implements Sender {
public void Send() {
System.out.println("This is sms sender...");
}
}
class SendMailFactory implements Provider {
public Sender produce() {
return new MailSender();
}
}
class SendSmsFactory implements Provider {
public Sender produce() {
return new SmsSender();
}
}
public class FactoryPattern {
public static void main(String[] args) {
Provider provider = new SendMailFactory();
Sender sender = provider.produce();
sender.Send();
}
}
<p><strong>三、代理模式</strong><br> 代理模式指给一个对象提供一个代理对象,并由代理对象控制对原对象的引用。代理可以分为静态代理和动态代理。<br> 通过代理模式,可以利用代理对象为被代理对象添加额外的功能,以此来拓展被代理对象的功能。可以用于计算某个方法执行时间,在某个方法执行前后记录日志等操作。</p>
<p><strong>1、静态代理:</strong><br> 静态代理需要我们写出代理类和被代理类,代理类和被代理类是一一对应,而且两者需要实现同一个接口,通过聚合使用代理类中有被代理类对象的引用,以此实现代理对象控制被代理对象的目的。</p>
<pre class="prettyprint"><code class="has-numbering" onclick="mdcp.copyCode(event)" style="position: unset;">// 代理类和被代理类共同实现的接口
interface IService {
void service();
}
```go
// 被代理类
class Service implements IService{
@Override
public void service() {
System.out.println("被代理对象执行相关操作");
}
}
// 代理类
class ProxyService implements IService{
// 持有被代理对象的引用
private IService service;
// 默认代理Service类
public ProxyService() {
this.service = new Service();
}
// 也可以代理实现相同接口的其他类
@param service
public ProxyService(IService service) {
this.service = service;
}
@Override
public void service() {
System.out.println("开始执行service()方法");
service.service();
System.out.println("service()方法执行完毕");
}
}
// 测试类
public class ProxyPattern {
public static void main(String[] args) {
IService service = new Service();
//传入被代理类的对象
ProxyService proxyService = new ProxyService(service);
proxyService.service();
}
}
2、动态代理:
动态代理常用于有若干个被代理的对象,且为每个被代理对象添加的功能是相同的(例如在每个方法运行前后记录日志)。
动态代理的代理类不需要我们编写,由Java自动产生代理类源代码并进行编译最后生成代理对象。
创建动态代理对象的步骤:
- 指明一系列的接口来创建一个代理对象
- 创建一个调用处理器(InvocationHandler)对象
- 将这个代理指定为某个其他对象的代理对象
- 在调用处理器的invoke()方法中采取代理,一方面将调用传递给真实对象,另一方面执行各种需要的操作
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 代理类和被代理类共同实现的接口
interface IService {
void service();
}
class Service implements IService{
@Override
public void service() {
System.out.println("被代理对象执行相关操作");
}
}
class ServiceInvocationHandler implements InvocationHandler {
// 被代理的对象
private Object srcObject;
public ServiceInvocationHandler(Object srcObject) {
this.srcObject = srcObject;
}
@Override
public Object invoke(Object proxyObj, Method method, Object[] args) throws Throwable {
System.out.println("开始执行"+method.getName()+"方法");
//执行原对象的相关操作,容易忘记
Object returnObj = method.invoke(srcObject,args);
System.out.println(method.getName()+"方法执行完毕");
return returnObj;
}
}
public class ProxyPattern {
public static void main(String[] args) {
IService service = new Service();
Class<? extends IService> clazz = service.getClass();\
IService proxyService = (IService) Proxy.newProxyInstance(clazz.getClassLoader(),
clazz.getInterfaces(), new ServiceInvocationHandler(service));
proxyService.service();
}
}
四、策略模式
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。
// 抽象算法的策略类,定义所有支持的算法的公共接口
abstract class Strategy {
// 算法方法
public abstract void AlgorithmInterface();
}
// 具体算法A
class ConcreteStrategyA extends Strategy {
//算法A实现方法
@Override
public void AlgorithmInterface() {
System.out.println("算法A的实现");
}
}
// 具体算法B
class ConcreteStrategyB extends Strategy {
// 算法B实现方法
@Override
public void AlgorithmInterface() {
System.out.println("算法B的实现");
}
}
// 具体算法C
class ConcreteStrategyC extends Strategy {
@Override
public void AlgorithmInterface() {
System.out.println("算法C的实现");
}
}
// 上下文,维护一个对策略类对象的引用
class Context {
Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void contextInterface(){
strategy.AlgorithmInterface();
}
}
// 客户端代码:实现不同的策略
public class StrategyPattern {
public static void main(String[] args) {
Context context;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}
五、观察者模式与发布/订阅模式区别
1、观察者模式:
目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。
比如有个“天气中心”的具体目标A,专门监听天气变化,而有个显示天气的界面的观察者B,B就把自己注册到A里,当A触发天气变化,就调度B的更新方法,并带上自己的上下文。
2、发布/订阅模式:
订阅者把自己想订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。
比如有个界面是实时显示天气,它就订阅天气事件(注册到调度中心,包括处理程序),当天气变化时(定时获取数据),就作为发布者发布天气信息到调度中心,调度中心就调度订阅者的天气处理程序。
总结:
- 从两张图片可以看到,最大的区别是调度的地方。
虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会。 - 两种模式都可以用于松散耦合,改进代码管理和潜在的复用。
六、适配器模式
适配器模式是将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分三类:类的适配器模式、对象的适配器模式和接口的适配器模式。
1、类的适配器模式:
class Source {
public void method1() {
System.out.println("This is original method...");
}
}
interface Targetable {
// 与原类中的方法相同
public void method1();
// 新类的方法
public void method2();
}
class Adapter extends Source implements Targetable {
@Override
public void method2() {
System.out.println("This is the targetable method...");
}
}
public class AdapterPattern {
public static void main(String[] args) {
Targetable targetable = new Adapter();
targetable.method1();
targetable.method2();
}
}
class Source { public void method1() { System.out.println("This is original method..."); } } interface Targetable { // 与原类中的方法相同 public void method1(); // 新类的方法 public void method2(); } class Wrapper implements Targetable { private Source source; public Wrapper(Source source) { super(); this.source = source; } @Override public void method1() { source.method1(); } @Override public void method2() { System.out.println("This is the targetable method..."); } } public class AdapterPattern { public static void main(String[] args) { Source source = new Source(); Targetable targetable = new Wrapper(source); targetable.method1(); targetable.method2(); } }
3、接口适配器模式:
接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。/** * 定义端口接口,提供通信服务 */ interface Port { // 远程SSH端口为22 void SSH(); // 网络端口为80 void NET(); // Tomcat容器端口为8080 void Tomcat(); // MySQL数据库端口为3306 void MySQL(); } /** * 定义抽象类实现端口接口,但是什么事情都不做 */ abstract class Wrapper implements Port { @Override public void SSH() { } @Override public void NET() { } @Override public void Tomcat() { } @Override public void MySQL() { } } /** * 提供聊天服务 * 需要网络功能 */ class Chat extends Wrapper { @Override public void NET() { System.out.println("Hello World..."); } } /** * 网站服务器 * 需要Tomcat容器,Mysql数据库,网络服务,远程服务 */ class Server extends Wrapper { @Override public void SSH() { System.out.println("Connect success..."); } @Override public void NET() { System.out.println("WWW..."); } @Override public void Tomcat() { System.out.println("Tomcat is running..."); } @Override public void MySQL() { System.out.println("MySQL is running..."); } } public class AdapterPattern { private static Port chatPort = new Chat(); private static Port serverPort = new Server(); public static void main(String[] args) { // 聊天服务 chatPort.NET(); // 服务器 serverPort.SSH(); serverPort.NET(); serverPort.Tomcat(); serverPort.MySQL(); } }
七、责任链模式
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。Tomcat中的Filter就是使用了责任链模式,创建一个Filter除了要在web.xml文件中做相应配置外,还需要实现javax.servlet.Filter接口。八、装饰者模式
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。interface Shape { void draw(); } /** * 实现接口的实体类 */ class Rectangle implements Shape { @Override public void draw() { System.out.println("Shape: Rectangle..."); } } class Circle implements Shape { @Override public void draw() { System.out.println("Shape: Circle..."); } } /** * 创建实现了 Shape 接口的抽象装饰类。 */ abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape) { this.decoratedShape = decoratedShape; } @Override public void draw() { decoratedShape.draw(); } } /** * 创建扩展自 ShapeDecorator 类的实体装饰类。 */ class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { decoratedShape.draw(); setRedBorder(decoratedShape); } private void setRedBorder(Shape decoratedShape) { System.out.println("Border Color: Red"); } } /** * 使用 RedShapeDecorator 来装饰 Shape 对象。 */ public class DecoratorPattern { public static void main(String[] args) { Shape circle = new Circle(); Shape redCircle = new RedShapeDecorator(new Circle()); Shape redRectangle = new RedShapeDecorator(new Rectangle()); System.out.println("Circle with normal border"); circle.draw(); System.out.println("\nCircle of red border"); redCircle.draw(); System.out.println("\nRectangle of red border"); redRectangle.draw(); } }