1、单例设计模式(饿汉式/懒汉式):
概念:保证类在内存中只有一个对象
思路:
- 私有构造方法,其他类不能再访问该构造方法了
- 创建本类对象(就在本类里创建),将对象的应用作为成员变量,并私有静态化(在这里又分为饿汉式和懒汉式,饿汉式直接引用连接对象,而懒汉式在第二步先创建引用,在第三步用一个判断语句,如果引用没有连接对象,就创建一个,如果有了,直接返回该引用)
- 对外提供获取对象引用的方法getClass()
饿汉式和懒汉式的区别:
- 饿汉式是空间换时间,懒汉式是时间换空间(不推荐)
- 在多线程访问时,饿汉式不会创建多个访问对象,而懒汉式会(也就是说饿汉线程安全,懒汉不安全,可以加个同步锁synchronized)
代码实例:
package cn.xinhua;
public class ThreadTest {
public static void main(String[] args) {
/*
* 饿汉式
*/
class Singleton1 {
// 1. 私有构造方法,其他类不能再访问该构造方法了
private Singleton1() {
}
// 2. 创建本类对象(就在本类里创建),将对象的应用作为成员变量,并私有静态化
private static Singleton1 s = new Singleton1();
// 3. 对外提供获取对象引用的方法getClass()
public static Singleton1 getS() {
return s;
}
}
/*
* 懒汉式:单例的延迟加载模式
*/
class Singleton2 {
// 1. 私有构造方法,其他类不能再访问该构造方法了
private Singleton2() {
}
// 2. 创建本类对象的引用(先不着急链接对象)
private static Singleton2 s ;
// 3. 对外提供获取对象引用的方法getClass(),如果为引用为空就创建一个,不为空(已经创建过),就返回
public static Singleton2 getS() {
if(s == null) {
//多线程时有隐患,线程1等待,线程2等待,就会创建多个对象
s = new Singleton2();
}
return s;
}
}
/*
* 第三种单例模式,直接将引用final
*/
class Singleton3 {
// 1. 私有构造方法,其他类不能再访问该构造方法了
private Singleton3() {
}
// 2. 创建本类对象的引用对象,直接final
private static final Singleton3 s = new Singleton3();
}
2、简单工厂模式:
简单工厂模式又叫静态工厂方法模式,定义了一个具体的工厂类负责创建类的对象
- 优点:客户端不需要再负责对象的创建,从而明确了各个类的指责
- 缺点:静态工厂类需要负责所有对象的创建,,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断修改工厂类,不利于后期维护
代码演示:
创建一个AnimalFactory工厂类如下
(其中Dog和Cat都是抽象类Animal的子类,重写了eat方法)
package cn.xinhua;
public class AnimalFactory {
public Animal createAnimal(String animal) { // 父类引用指向子类对象
if ("Dog".equals(animal)) {
return new Dog();
} else if ("Cat".equals(animal)) {
return new Cat();
} else {
return null;
}
}
}
再来个测试类:
package cn.xinhua;
public class AnimalFactoryTest {
public static void main(String[] args) {
AnimalFactory af = new AnimalFactory();
Dog an = (Dog) af.createAnimal("Dog");
System.out.println(an);
an.eat();
}
}
输出:
cn.xinhua.Dog@70dea4e(还没有重写子类的toString方法,所以打印的是地址值)
狗吃肉
3、工厂模式:
工厂模式算是上面的简单工厂模式的进阶,更容易扩展,但也更复杂了
这里将工厂变为动态的(相比于上面的静态),将工厂类变为实现一个工厂类的接口,重写creatAnimal的方法,这样你每次增加一个动物,都需要实现一个对用的具体的工厂类,然后创建这个动物就用这个动物的工厂类(更加复杂了,但是就像印钱一样,只能国家印,要创建对象只能继承这个工厂类并重写方法)
- 优点:客户端不需要再负责对象的创建,从而明确了各个类的指责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂即可(从Animal那里继承的子类和从Factory那里实现的工厂),不影响已有代码,后期维护容易,增强了系统的扩展性,感觉就是你要开个厂就需要向国家这个最大的厂报备一样
- 缺点:代码多代码多代码多
代码演示:
工厂接口:
package cn.xinhua;
public interface Factory {
public Animal createAniama();
}
Dog类的工厂类(实现了上面的工厂接口):
(每次创建一个对象都要相应地创建一个此类的工厂类)
package cn.xinhua;
public class DogFactory implements Factory {
@Override
public Animal createAniama() {
return new Dog();
}
}
再来个测试类:
先创建此类的工厂类对象,然后用这个工厂类对象创建此类的对象(好复杂,有毒!)
package cn.xinhua;
public class AnimalFactoryTest {
public static void main(String[] args) {
DogFactory dg = new DogFactory();
Dog dog = (Dog) dg.createAniama();
dog.eat();
}
}
输出:狗吃肉
4、适配器模式:
适配器是实现了监听器接口下面的抽象类,因为我没有看GUI,所以就不用监听器的概念了
定义:
- 通常接口中有很多个方法,而程序中不一定所有的都用得到,但又必须重写,很繁琐
- 适配器简化了这些操作,我们定义的类只要继承适配器,然后重写需要的方法即可
原理:
- 适配器就是一个类,实现了接口,重写了其中的所有的方法,但方法都是空的
- 适配器类定义成抽象的,因为创建该类的对象,方法都是空的没有意义
代码实例:
package cn.xinhua;
public class AnimalFactoryTest {
//监听器接口,就是有很多方法的接口
public interface Listen {
public void method1();
public void method2();
public void method3();
public void method4();
}
//适配器
abstract class Middle implements Listen {
@Override
public void method1() {
}
@Override
public void method2() {
}
@Override
public void method3() {
}
@Override
public void method4() {
}
}
//继承适配器的类,不用实现监听器中全部的方法了
class Men extends Middle {
public void method1() {
System.out.println(1);
System.out.println(2);
System.out.println(3);
}
}
}
5、模板方法设计模式:
具体看:
设计模式之 - 模板模式(Template Pattern)
其实就是分权,国家定义一个大概的方法/模板,不会面面俱到,然后地方上实现具体的做法,有点像类的继承的思想,增加了代码的泛化能力