我理解的Java设计模式
1、工厂模式
什么是工厂模式?
映射到现实就是有这么一个工厂,生产好多产品,不用的客户需要不同的产品,所有客户只需要告诉工厂需要什么,工厂就生产什么。在Java的工厂模式中,一个产品就是一个对象,也就是有这么一个类,需要什么对象就创建什么对象。
工厂模式的实现
实现的方式有好几种,有工厂方法模式,抽象工厂模式等。这里就写一个常用的抽象工厂模式demo。
有一个生产电脑配件的工厂(抽象工厂模式)
1、创建一个抽象工厂
public abstract class AbstractComputerFactory {
public abstract ComputerCPU produceComputerCPU();
public abstract MainBoard produceMainBoard();
public abstract HardDisk produceHardDisk();
}
2、具体的实现工厂
public class ComputerFactory extends AbstractComputerFactory {
@Override
public ComputerCPU produceComputerCPU() {
return new ComputerCPU();
}
@Override
public MainBoard produceMainBoard() {
return new MainBoard();
}
@Override
public HardDisk produceHardDisk() {
return new HardDisk();
}
}
3、具体的电脑组件
CPU组件:
public class ComputerCPU implements ComputerCpuInterface{
@Override
public void run() {
System.out.println("ComputerCPU.run()");
}
}
public interface ComputerCpuInterface {
void run();
}
主板组件:
public class MainBoard implements MainBoardInterface {
@Override
public void run() {
System.out.println("MainBoard.run()");
}
}
public interface MainBoardInterface {
void run();
}
硬盘组件:
public class HardDisk implements HardDiskInterface {
@Override
public void run() {
System.out.println("HardDisk.run()");
}
}
public interface HardDiskInterface {
void run();
}
4、测试
ComputerFactory computerFactory = new ComputerFactory();
// 生产一个CPU
ComputerCPU cpu = computerFactory.produceComputerCPU();
cpu.run();
// 生产一个硬盘
HardDisk hardDisk = computerFactory.produceHardDisk();
hardDisk.run();
// 生产一个主板
MainBoard board = computerFactory.produceMainBoard();
board.run();
2、单例模式
1、什么是单列例模式?
顾名思义,就是在程序中的某个类只保留一个对象,只能存在一个实例。单例模式有懒汉模式,恶汉模式两种。
2、懒汉模式
顾名思义,就是单例创建比较懒,在需要的时候才创建,而不是一开始就创建好了。这种模式存在现行安全问题,如果有多个线程并发访问就有可能存在多个实例,所以不推荐直接使用。
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
有人说改成下面这种使用synchronized 加锁的方式就线性安全了。可是我看过一个大牛的教学视频证明了也并非如此,而且效率大大的降低了,故,不推荐使用。
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
// 对象好懒好懒,需要时才创建
instance = new LazySingleton();
}
return instance;
}
}
3、饿汉模式
顾名思义,就是这个对象好饿好饿,不在需要的时候才创建,而是一开始类初始化的时候就创建,这样可以避免线程安全问题,但是浪费内存空间,不推荐
public class HungrySingleton {
// 对象好饿好饿,一开始就创建
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return instance;
}
}
4、懒汉还是饿汉的选择
如果对象经常访问就选饿汉模式,如果不经常访问就选懒汉模式。
5、终极的单例模式
考虑到线性安全和效率的问题,我结合静态内部类写了一个终极的单例模式,使用的时候照搬下面的代码就行,保证线性安全和效率。
public class LazySingleton {
private static boolean initialized = false;
/***
* 静态的内部类(寄生虫),解决多线程安全问题
*/
private static class LazyHolder {
private static final LazySingleton LAZY = new LazySingleton();
}
private LazySingleton() {
// 解决反射破坏到单例
synchronized (LazySingleton.class) {
if (!initialized) {
initialized = true;
} else {
throw new RuntimeException("禁止初始化...");
}
}
}
public static LazySingleton getInstance() {
return LazyHolder.LAZY;
}
}
3、Builder模式
1、什么是Builder模式?
有些对象的创建也太复杂了,需要很多的参数,创建起来真是烦人而且容易出错了,正因为如此才有了该模式。使用简单的对象去一步一步的去构建一个复杂的对象,这就是Builder模式。
2、举个栗子
比如有下面这么一个对象
public class Person {
private final int id;
private final String name;
private final int age;
private final String sex;
private final String phone;
private final String address;
public Person(int id, String name) {
this(id, name, 0);
}
public Person(int id, String name, int age) {
this(id, name, age, null);
}
public Person(int id, String name, int age, String sex) {
this(id, name, age, sex, null);
}
public Person(int id, String name, int age, String sex, String phone) {
this(id, name, age, sex, phone, null);
}
public Person(int id, String name, int age, String sex, String phone, String address) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.phone = phone;
this.address = address;
}
}
当需要创建一个新的对象时就傻傻不知道到底该调用哪个构造方法了吧。虽然有get和set方法,但是JavaBean模式本身也存在重大的缺点,在构造过程中被分到了几个调用中。下面就改造成使用Builder模式试试看。
public class Person {
private int id;
private String name;
private int age;
private String sex;
private String phone;
private String address;
public Person(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.age = builder.age;
this.sex = builder.sex;
this.phone = builder.phone;
this.address = builder.address;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", phone='" + phone + '\'' +
", address='" + address + '\'' +
'}';
}
public static class Builder {
private int id;
private String name;
private int age;
private String sex;
private String phone;
private String address;
public Builder(int id, String name) {
this.id = id;
this.name = name;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder sex(String sex) {
this.sex = sex;
return this;
}
public Builder phone(String phone) {
this.phone = phone;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Person build() {
return new Person(this);
}
}
}
然后这样创建对象,是不是简单多了,除了必要参数,想填什么就填什么,不需要构造方法那样,不填的参数还要设null等。
Person person = new Person.Builder(23, "Tom")
.address("北京")
.age(18)
.phone("13800000000")
.sex("魔").build();
System.out.println(person.toString());
打印:Person{id=23, name=’Tom’, age=18, sex=’魔’, phone=’13800000000’, address=’北京’}
4、适配器模式
1、类适配器模式
接口A中没有想要的方法,接口A又不能被更改,但是接口B中有,这时就可以创建一个适配器PAdapter来中转,达到访问接口B中的方法。实现方法如下:
// 接口A中有一个方法a
public interface A {
void a();
}
// 接口B中有一个方法B
public interface B {
void b();
}
// 接口B的实现类BImpl中的b方法就是我们的目标方法
public class BImpl implements B {
@Override
public void b() {
System.out.println(" 接口B中的我们想要的b方法");
}
}
// 适配器P继承BImpl实现A,在重写的a方法中调用继承的b方法,达到在A接口中访问B接口中的b方法
public class PAdapter extends BImpl implements A {
@Override
public void a() {
b();
}
}
// 测试方法
public static void main(String[] args){
A a = new PAdapter();
a.a();
}
这样我们就实现了一个简单的类适配器!
2、对象适配器模式
作用同类适配器模式,实现方式稍有些差别,在适配器PAdapter中创建一个私有的B变量和一个带B参数的构造方法来给B变量赋值,达到访问b方法的目的。改动如下:
// 改造的PAdapter
public class PAdapter implements A {
private B b;
public PAdapter(B b) {
this.b = b;
}
@Override
public void a() {
b.b();
}
}
// 测试方法
public static void main(String[] args){
A a = new PAdapter(new BImpl());
a.a();
}
3、接口适配器模式
接口A中有超多的方法,但是我们不想把它们都实现,只想实现其中的几个,这是就可用接口适配器模式,把接口类间接改成抽象类,这样就不必每次直接实现接口A所有的方法而使得很多方法置空,代码也臃肿。实现如下:
// 超多方法的接口A
public interface A {
void a();
void b();
void c();
void d();
void e();
void f();
}
// 抽象类适配器实现接口A
public abstract class Adapter implements A {
@Override
public void a(){}
@Override
public void b(){}
@Override
public void c(){}
@Override
public void d(){}
@Override
public void e(){}
@Override
public void f(){}
}
// 实现想要实现的接口A方法
public class AImpl extends Adapter {
@Override
public void a(){
System.out.println("接口A的a方法");
}
@Override
public void d(){
System.out.println("接口A的d方法");
}
}
// 测试方法
public static void main(String[] args) {
A a = new AImpl();
a.a();
a.d();
}
5、过滤器模式
转载阅读:过滤器模式