java设计模式

分为三类

创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式,建造者模式,原型模式。
结构型模式(7种):适配器模式、装饰器模式、代理模式,外观模式、桥接模式、组合模式、享元模式。
行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

遵循的原则

1、开闭原则(Open Close Principle)
  对扩展开放,对修改关闭。
2、里氏代换原则(Liskov Substitution Principle)
  只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
3、依赖倒转原则(Dependence Inversion Principle)
  这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
  使用多个隔离的接口来降低耦合度。
5、迪米特法则(最少知道原则)(Demeter Principle)
  一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
  原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。

几种常用的设计模式

单例模式

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例。
在Spring中创建的Bean实例默认都是单例模式存在的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.design.model.singleton;
/**
* 单利模式懒汉式
* 全局的单例实例在第一次被使用时构建
* @author ming
*/
public class Sluggard {
private Sluggard() {}

private static volatile Sluggard singleton = null;

public static Sluggard getInstance() {
synchronized(Sluggard.class) {
if(singleton==null) {
singleton = new Sluggard();
}
}
return singleton;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.design.model.singleton;
/**
* 单利模式饿汉式
* 全局的单例实例在类装载时构建
* @author ming
*/
public class Hunger {

private Hunger() {}

private static final Hunger singleton = new Hunger();

public static Hunger getInstance(){
return singleton ;
}
}

工厂模式

静态工厂模式-工厂方法

常用的工厂模式是静态工厂,利用static方法,作为一种类似于常见的工具类Utils等辅助效果,一般情况下工厂类不需要实例化。

1
2
3
4
5
package com.design.model.staticfactory;

public interface Wine {
void degree();
}

1
2
3
4
5
6
7
8
9
10
package com.design.model.staticfactory;

public class A implements Wine{

@Override
public void degree() {
System.out.println("42度白酒");
}

}

1
2
3
4
5
6
7
8
9
10
package com.design.model.staticfactory;

public class B implements Wine{

@Override
public void degree() {
System.out.println("48度白酒");
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.design.model.staticfactory;
public class StaticFactory {
private StaticFactory() {}

public static Wine getA(){ return new A(); }
public static Wine getB(){ return new B(); }

static class Client{
//客户端代码只需要将相应的参数传入即可得到对象
//用户不需要了解工厂类内部的逻辑。
public Wine get(String name){
Wine wine = null ;
if ( name.equals("A")) {
wine = StaticFactory.getA();
}else if ( name.equals("B")){
wine = StaticFactory.getB();
}
return wine;
}
}
public static void main(String[] args) {
Client cli = new Client();
Wine wine = cli.get("A");
wine.degree();
}
}

抽象工厂模式

一个基础接口定义了功能,每个实现接口的子类就是产品,然后定义一个工厂接口,实现了工厂接口的就是工厂,这时候,接口编程的优点就出现了,我们可以新增产品类(只需要实现产品接口),只需要同时新增一个工厂类,客户端就可以轻松调用新产品的代码。
抽象工厂的灵活性就体现在这里,无需改动原有的代码,毕竟对于客户端来说,静态工厂模式在不改动StaticFactory类的代码时无法新增产品,如果采用了抽象工厂模式,就可以轻松的新增拓展类。
简单示例:
1.抽象产品接口:定义产品的接口,公共的暴露方法。便于实际的产品类实现。
2.具体的产品类:包含实际产品的类的逻辑处理。
3.抽象工厂接口:定义产生系列对象的接口。
4.具体的工厂实现:实现抽象的接口工厂,返回具体的产品类的实现。

1
2
3
4
5
6
7
8
package com.design.model.abstractfactory;
/**
* 抽象产品角色 吃早餐接口
* @author ming
*/
public interface IBreakFast {
void eat();
}

1
2
3
4
5
6
7
8
9
10
11
package com.design.model.abstractfactory;
/**
* 具体产品角色,喝牛奶
* @author ming
*/
public class Milk implements IBreakFast {
@Override
public void eat() {
System.out.println("喝牛奶!");
}
}

1
2
3
4
5
6
7
8
9
10
11
package com.design.model.abstractfactory;
/**
* 具体产品角色,吃橘子
* @author ming
*/
public class Orange implements IBreakFast {
@Override
public void eat() {
System.out.println("吃橘子!");
}
}

1
2
3
4
5
6
7
8
package com.design.model.abstractfactory;
/**
* 定义好抽象的工厂接口,一系列的获取实例的接口方法
* @author ming
*/
public interface IAbstractFactory {
IBreakFast getBreakFast();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.design.model.abstractfactory;
/**
* 定义具体的工厂生产类,具体的产品实例返回
* @author ming
*/
public class HighPersonFactory implements IAbstractFactory {

@Override
public IBreakFast getBreakFast() {
// TODO Auto-generated method stub
return new Milk();
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.design.model.abstractfactory;
/**
* 定义具体的工厂生产类,具体的产品实例返回
* @author ming
*/
public class LowPersonFactory implements IAbstractFactory {

@Override
public IBreakFast getBreakFast() {
return new Orange();
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.design.model.abstractfactory;
/**
* 测试
* @author ming
*/
public class AbstractFactoryTest {
public static void main(String[] args) {
IAbstractFactory factory = new HighPersonFactory();
IBreakFast breakFast = factory.getBreakFast();
breakFast.eat();

IAbstractFactory factory2 = new LowPersonFactory();
IBreakFast breakFast2 = factory2.getBreakFast();
breakFast2.eat();
}
}

这样使用过程城中,只要注入抽象的工厂接口,具体的产品的产生,会在实际的子类工厂类中产生,也可以随意的添加和修改实际子类工厂类,而不需要改变既有的代码设计。

装饰模式(Decorator)

给一类对象增加新的功能,装饰类对装饰对象没有控制权,只能为其增加一层装饰,以加强被装饰对象的功能

1
2
3
4
5
6
7
8
package com.design.model.decorator;
/**
* 定义接口
* @author ming
*/
public interface IRunner {
public void run();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.design.model.decorator;
/**
* 接口具体实现
* @author ming
*
*/
public class Runner implements IRunner {

@Override
public void run() {
System.out.println("运动员在跑步...");
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.design.model.decorator;
/**
* 装饰类
* @author ming
*/
public class RunnerWithJet implements IRunner {
private IRunner runner;

public RunnerWithJet(IRunner runner) {
this.runner = runner;
}

@Override
public void run() {
System.out.println("给运动员屁股后加一个推进装置...");
runner.run();
}

public static void main(String[] args) {
IRunner runner = new Runner();
IRunner superRunner = new RunnerWithJet(runner);
System.out.println("有人请求加强版运动员跑步...");
superRunner.run();
}

}

代理模式(Proxy)

客户端通过代理类访问,代理类实现具体的实现细节,客户只需要使用代理类即可实现操作。
这种模式可以对旧功能进行代理,用一个代理类调用原有的方法,且对产生的结果进行控制。

1
2
3
4
5
6
7
8
package com.design.model.proxy;
/**
* 定义接口
* @author ming
*/
public interface IRunner {
public void run();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.design.model.proxy;
/**
* 接口具体实现
* @author ming
*
*/
public class Runner implements IRunner {

@Override
public void run() {
System.out.println("运动员在跑步...");
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.design.model.proxy;

public class RunnerAgent implements IRunner {
private IRunner runner;
private boolean flag;

public RunnerAgent(IRunner runner,boolean flag) {
this.runner = runner;
this.flag = flag;
}

@Override
public void run() {
if(flag) {
System.out.println("代理人安排运动员跑步...");
runner.run();
}else {
System.out.println("代理人有事情,不安排运动员跑步了...");
}
}

public static void main(String[] args) {
IRunner runner = new Runner();
IRunner agent = new RunnerAgent(runner,true);

System.out.println("有人请求代理人让运动员跑步...");
agent.run();
}

}

适配器模式(Adapter)

将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
适配器模式的别名为包装器(Wrapper)模式,它既可以作为类结构型模式,也可以作为对象结构型模式。在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。

类适配器模式

原理:通过继承来实现适配器功能。
当我们要访问的接口A中没有我们想要的方法 ,却在另一个接口B中发现了合适的方法,我们又不能改变访问接口A,在这种情况下,我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法(虽然它目前不是我们的菜),然后再继承接口B的实现类BB,这样我们可以在适配器P中访问接口B的方法了,这时我们在适配器P中的接口A方法中直接引用BB中的合适方法,这样就完成了一个简单的类适配器。

1
2
3
public interface Ps2 {
void isPs2();
}

1
2
3
public interface Usb {
void isUsb();
}

1
2
3
4
5
6
7
8
public class Usber implements Usb {

@Override
public void isUsb() {
System.out.println("USB口");
}

}

1
2
3
4
5
6
7
8
public class Adapter extends Usber implements Ps2 {

@Override
public void isPs2() {
isUsb();
}

}

1
2
3
4
5
6
public class Clienter {
public static void main(String[] args) {
Ps2 p = new Adapter();
p.isPs2();
}
}

对象适配器模式

原理:通过组合来实现适配器功能。
当我们要访问的接口A中没有我们想要的方法 ,却在另一个接口B中发现了合适的方法,我们又不能改变访问接口A,在这种情况下,我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法(虽然它目前不是我们的菜),然后在适配器P中定义私有变量C(对象)(B接口指向变量名),再定义一个带参数的构造器用来为对象C赋值,再在A接口的方法实现中使用对象C调用其来源于B接口的方法。

1
2
3
public interface Ps2 {
void isPs2();
}

1
2
3
public interface Usb {
void isUsb();
}

1
2
3
4
5
6
7
8
public class Usber implements Usb {

@Override
public void isUsb() {
System.out.println("USB口");
}

}

1
2
3
4
5
6
7
8
9
10
11
12
public class Adapter implements Ps2 {

private Usb usb;
public Adapter(Usb usb){
this.usb = usb;
}
@Override
public void isPs2() {
usb.isUsb();
}

}

1
2
3
4
5
6
7
8
public class Clienter {

public static void main(String[] args) {
Ps2 p = new Adapter(new Usber());
p.isPs2();
}

}

接口适配器模式

原理:通过抽象类来实现适配,这种适配稍别于上面所述的适配。
当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,哪怕我们仅仅是对不需要的方法进行置空(只写一对大括号,不做具体方法实现)也会导致这个类变得臃肿,调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。

1
2
3
4
5
6
7
8
public interface A {
void a();
void b();
void c();
void d();
void e();
void f();
}

1
2
3
4
5
6
7
8
public abstract class Adapter implements A {
public void a(){}
public void b(){}
public void c(){}
public void d(){}
public void e(){}
public void f(){}
}

1
2
3
4
5
6
7
8
public class Ashili extends Adapter {
public void a(){
System.out.println("实现A方法被调用");
}
public void d(){
System.out.println("实现d方法被调用");
}
}

1
2
3
4
5
6
7
8
9
public class Clienter {

public static void main(String[] args) {
A a = new Ashili();
a.a();
a.d();
}

}

建造者模式(Builder)

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class Builder {

static class Student{
String name = null ;
int number = -1 ;
String sex = null ;
int age = -1 ;
String school = null ;

     //构建器,利用构建器作为参数来构建Student对象
static class StudentBuilder{
String name = null ;
int number = -1 ;
String sex = null ;
int age = -1 ;
String school = null ;
public StudentBuilder setName(String name) {
this.name = name;
return this ;
}

public StudentBuilder setNumber(int number) {
this.number = number;
return this ;
}

public StudentBuilder setSex(String sex) {
this.sex = sex;
return this ;
}

public StudentBuilder setAge(int age) {
this.age = age;
return this ;
}

public StudentBuilder setSchool(String school) {
this.school = school;
return this ;
}
public Student build() {
return new Student(this);
}
}

public Student(StudentBuilder builder){
this.age = builder.age;
this.name = builder.name;
this.number = builder.number;
this.school = builder.school ;
this.sex = builder.sex ;
}
}

public static void main( String[] args ){
Student a = new Student.StudentBuilder().setAge(13).setName("LiHua").build();
Student b = new Student.StudentBuilder().setSchool("sc").setSex("Male").setName("ZhangSan").build();
}
}

策略模式

其思想是针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。
TreeSet集合就采用了经典的策略模式的思想。
策略模式体现了面向对象程序设计中非常重要的两个原则:
1.封装变化的概念。
2.编程中使用接口,而不是使用的是具体的实现类(面向接口编程)。
实现一个加减乘除的功能,如下

1
2
3
4
5
6
7
8
9
package com.design.model.strategy;
/**
* 定义抽象策略角色
* @author ming
*/
public interface Strategy {
//定义两个数可以计算
public int calc(int num1,int num2);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.design.model.strategy;
/**
* 定义加法策略
* @author ming
*/
public class AddStrategy implements Strategy {

@Override
public int calc(int num1, int num2) {
return num1+num2;
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.design.model.strategy;
/**
* 定义减法策略
* @author ming
*/
public class SubstractStrategy implements Strategy {

@Override
public int calc(int num1, int num2) {
return num1-num2;
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.design.model.strategy;
/**
* 环境角色
*/
public class Environment {
public Strategy strategy;

public Environment(Strategy strategy) {
this.strategy = strategy;
}

public int calulate(int a,int b) {
return strategy.calc(a, b);
}

public static void main(String[] args) {
Strategy strategy = new AddStrategy();
Environment environment = new Environment(strategy);
System.out.println(environment.calulate(20, 30));
}

}

推荐一本让人看了睡觉的好书

《java多线程编程(设计模式篇)-黄海文》

参考地址

http://www.cnblogs.com/malihe/p/6891920.html
https://www.cnblogs.com/lilin0719/p/5313886.html
https://www.cnblogs.com/luoxn28/p/5535877.html
https://www.cnblogs.com/songyaqi/p/4805820.html
http://baijiahao.baidu.com/s?id=1601547440739500969&wfr=spider&for=pc

本文标题:java设计模式

文章作者:wangming

发布时间:2019年01月22日 - 16:50:15

最后更新:2019年01月23日 - 00:16:03

原始链接:https://syxiaowanzi.github.io/2019/01/22/java设计模式/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%