这篇文章讲述的是java设计模式,包括单例模式、工厂模式、代理模式,如有错误或不当之处,希望各位大神批评指正。
什么是设计模式?
设计模式:是指在大量的理论和实践中总结和理论化之后,优选的代码结构、编程风格、以及解决问题的思考模式。正如数学中的公式的使用一样。
包括:
- 单例模式
- 模板模式
- 工厂模式
- 代理模式
- 等等…
单例模式
什么是单例模式?
单例模式是指,采用某种手段或者方法,保证整个软件系统中只能存在一个对象的实例,并且该实例只提供创建该对象的方法。
使用情况及优缺点
- 使用情况:当您想控制实例数目,节省系统资源的时候,和一个全局使用的类频繁地创建与销毁的时候
- 优点:节省系统资源的开销,避免内存的重复使用
- 缺点:没有接口,不能继承
单例模式的例子
饿汉式
package com.cn.cmc.javadesignstyle;
public class SingletonDemo {
//获取一个单例的实例
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance() ;
Singleton singleton2 = Singleton.getInstance() ;
System.out.println(singleton1 == singleton2);
singleton1.claim();
}
}
/**
* 单例模式:程序运行中只能存在一个对象的实例
*
* 设计步骤:1. 将构造器私有化,保证外部不能创建
* 2. 初始化实例
* 3. 私有化实例,向外界提供一个返回实例的接口
* 4. 次公共方法必须通过类来调用static
*/
class Singleton{
//将构造器私有化
private Singleton(){
}
//在内部初始化一个实例
//恶汉模式:在初始化类的时候直接实例化对象
private static Singleton singleton = new Singleton() ;
//懒汉模式:初始化时候不新建对象,在具体用到的时候在实例化
private static Singleton singleton2 = null ;
//向外部提供一个返回实例方法
//饿汉
public static Singleton getInstance() {
return singleton;
}
}
懒汉式
package com.cn.cmc.javadesignstyle;
public class SingletonDemo {
//获取一个单例的实例
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance() ;
Singleton singleton2 = Singleton.getInstance() ;
System.out.println(singleton1 == singleton2);
singleton1.claim();
}
}
/**
* 单例模式:程序运行中只能存在一个对象的实例
*
* 设计步骤:1. 将构造器私有化,保证外部不能创建
* 2. 初始化实例
* 3. 私有化实例,向外界提供一个返回实例的接口
* 4. 次公共方法必须通过类来调用static
*/
class Singleton{
//将构造器私有化
private Singleton(){
}
//在内部初始化一个实例
//懒汉模式:初始化时候不新建对象,在具体用到的时候在实例化
private static Singleton singleton2 = null ;
//向外部提供一个返回实例方法
public synchronized static Singleton getInstance2(){
if(singleton2 == null){
singleton2 = new Singleton() ;
}
return singleton2 ;
}
}
注:使用懒汉模式时要注意线程安全问题,需要使用synchronized来控制进入创建实例方法的线程
静态内部类式
package com.cn.cmc.javadesignstyle;
public class SingletonDemo {
//获取一个单例的实例
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance() ;
Singleton singleton2 = Singleton.getInstance() ;
System.out.println(singleton1 == singleton2);
}
}
/**
* 单例模式:程序运行中只能存在一个对象的实例
*
* 设计步骤:1. 将构造器私有化,保证外部不能创建
* 2. 初始化实例
* 3. 私有化实例,向外界提供一个返回实例的接口
* 4. 次公共方法必须通过类来调用static
*/
class Singleton{
//将构造器私有化
private Singleton(){
}
//静态内部类方式,在第一次使用时才会加载
private static class SingletonClassInstance{
private static final Singleton instance = new Singleton() ;
}
public static Singleton getInstance(){
return SingletonClassInstance.instance ;
}
}
枚举式
package com.cn.cmc.javadesignstyle;
public class SingletonDemo {
//获取一个单例的实例
public static void main(String[] args) {
Singleton singleton1 = Singleton.INSTANCE ;
Singleton singleton2 = Singleton.INSTANCE ;
System.out.println(singleton1 == singleton2);
}
}
/**
* 单例模式:程序运行中只能存在一个对象的实例
*
* 设计步骤:1. 将构造器私有化,保证外部不能创建
* 2. 初始化实例
* 3. 私有化实例,向外界提供一个返回实例的接口
* 4. 次公共方法必须通过类来调用static
*/
enum Singleton{
//枚举类本身就是单例
INSTANCE ;
//相关操作
public void operator(){
System.out.println("操作...");
}
}
单例模式总结
- 饿汉式自身线程安全,调用高效但不支持延迟加载
- 懒汉式需要synchronized保证线程安全,支持懒加载但调用低效
- 静态内部类方式自身线程安全,支持懒加载且效率高效
枚举式自身线程安全,编写方便效率高效但不支持懒加载
选用时:若占用资源少,不需要懒加载,枚举式好于饿汉式
若占用资源多,需要懒加载时,静态内部类式要好于懒汉式
模板模式
什么是模板模式
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
使用情况及优缺点
- 使用情况:一些方法通用,却在每一个子类都重新写了这一方法。
- 优点: 封装不变部分,扩展可变部分。 提取公共代码,便于维护。 行为由父类控制,子类实现。
- 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
模板模式的例子
package com.cn.cmc.javadesignstyle;
/**
* 模板模式:父类只规定有什么通用方法,具体的实现交给子类来执行
*
* 设计步骤:1. 将父类定义为抽象类
* 2. 将父类的方法定义为抽象方法
* 3.子类在继承父类时实现具体的方法
*/
//将父类定义为抽象类
abstract class Template{
//将父类中的方法定义为抽象方法
abstract void begin() ;
abstract void say() ;
abstract void end() ;
}
//子类在继承模板类时实现具体的方法
class Cat extends Template{
void begin() {
System.out.println("我是一只猫");
}
void say() {
System.out.println("喵喵喵~");
}
void end() {
System.out.println("说完了");
}
}
class Dog extends Template{
void begin() {
System.out.println("我是一只狗");
}
void say() {
System.out.println("汪汪汪!");
}
void end() {
System.out.println("说完了");
}
}
public class TemplatePattern {
public static void main(String[] args) {
//创建实现模板方法的类
Cat cat = new Cat() ;
Dog dog = new Dog() ;
cat.begin();
cat.say();
cat.end();
dog.begin();
dog.say();
dog.end();
}
}
工厂模式
什么是工厂模式?
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
使用情况及优缺点
- 使用情况:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
- 优点:一个调用者想创建一个对象,只要知道其名称就可以了。 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 屏蔽产品的具体实现,调用者只关心产品的接口。
- 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
工厂模式的例子
简单工厂模式
package com.cn.cmc.singleton;
/**
* 工厂模式:定义一个创建类的接口,并让其子类决定实现哪个工厂类,使创建者和调用者分离
* 简单工厂模式:对于同一等级结构的任一产品,对于新增加的产品需要修改已有代码
* 工厂方法模式:用来生产同一等级结构中的任一产品,对于新增加的产品支持
* 抽象工厂模式:用来生产不同产品族的全部产品
*
* 设计步骤:1.定义工厂类
* 2.定义创建类的接口
*/
/*工厂类*/
class AnimalFactory {
//工厂接口中只写获取类的方法
public static Sheep createSheep(){
return new Sheep() ;
}
public static Cow createCow(){
return new Cow() ;
}
}
/*接口类*/
interface Animal {
public void cry() ;
}
/*实现类*/
class Cow implements Animal{
public void cry() {
System.out.println("哞哞哞~");
}
}
class Sheep implements Animal{
public void cry(){
System.out.println("咩咩咩~");
}
}
public class SimpleFactory {
public static void main(String[] args) {
//工厂模式创建对象
Sheep sheep = AnimalFactory.createSheep() ;
Cow cow = AnimalFactory.createCow() ;
sheep.cry();
cow.cry();
}
}
工厂方法模式
package com.cn.cmc.factory;
/**
* 工厂模式:定义一个创建类的接口,并让其子类决定实现哪个工厂类,使创建者和调用者分离
* 简单工厂模式:对于同一等级结构的任一产品,对于新增加的产品需要修改已有代码
* 工厂方法模式:用来生产同一等级结构中的任一产品,对于新增加的产品支持
* 抽象工厂模式:用来生产不同产品族的全部产品
*
* 设计步骤:1.定义工厂类
* 2.定义创建类的接口
*/
/*工厂类*/
class AnimalFactory {
//工厂接口中只写获取类的方法
public static Sheep createSheep(){
return new Sheep() ;
}
public static Cow createCow(){
return new Cow() ;
}
}
/*接口类*/
interface Animal {
public void cry() ;
}
/*实现类*/
class Cow implements Animal{
public void cry() {
System.out.println("哞哞哞~");
}
}
class Sheep implements Animal{
public void cry(){
System.out.println("咩咩咩~");
}
}
public class SimpleFactory {
public static void main(String[] args) {
//工厂模式创建对象
Sheep sheep = AnimalFactory.createSheep() ;
Cow cow = AnimalFactory.createCow() ;
sheep.cry();
cow.cry();
}
}
抽象工厂模式
package com.cn.cmc.factory;
public class AbstractFactory {
/**
* 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
* 系统的产品有多于一个的产品族,而系统只消费其中某一族的产品时使用。
*/
public static void main(String[] args) {
Engine e = new LuxuryCarFactory().createEngine() ;
Tyre t = new LuxuryCarFactory().createTyre() ;
Seat s = new LuxuryCarFactory().createSeat() ;
e.run();
e.start();
t.revolve();
s.feel();
}
}
/*高端车生产工厂*/
class LuxuryCarFactory implements CarFactory{
@Override
public Seat createSeat() {
return new LuxurySeat();
}
@Override
public Tyre createTyre() {
return new LuxuryTyre();
}
@Override
public Engine createEngine() {
return new LuxuryEngine();
}
}
/*低端车生产工厂*/
class LowCarFactory implements CarFactory{
@Override
public Seat createSeat() {
return new LowSeat();
}
@Override
public Tyre createTyre() {
return new LowTyre();
}
@Override
public Engine createEngine() {
return new LowEngine();
}
}
/*汽车抽象工厂类*/
interface CarFactory{
Seat createSeat() ;
Tyre createTyre() ;
Engine createEngine() ;
}
/*座椅接口*/
interface Seat{
void feel() ;
}
/*座椅实现类-高端*/
class LuxurySeat implements Seat{
@Override
public void feel() {
System.out.println("高端座椅十分舒适");
}
}
/*座椅实现类-低端*/
class LowSeat implements Seat{
@Override
public void feel() {
System.out.println("低端座椅不舒服");
}
}
/*轮胎接口*/
interface Tyre{
void revolve() ;
}
/*轮胎实现类-高端轮胎*/
class LuxuryTyre implements Tyre{
@Override
public void revolve() {
System.out.println("高端轮胎不易磨损");
}
}
/*轮胎实现类-低端轮胎*/
class LowTyre implements Tyre{
@Override
public void revolve() {
System.out.println("低端轮胎易磨损");
}
}
/*引擎接口*/
interface Engine {
void run() ;
void start() ;
}
/*引擎实现类-高端*/
class LuxuryEngine implements Engine{
@Override
public void run() {
System.out.println("高端引擎马力大");
}
@Override
public void start() {
System.out.println("高端引擎转速快");
}
}
/*引擎实现类-低端*/
class LowEngine implements Engine{
@Override
public void run() {
System.out.println("低端引擎马力小");
}
@Override
public void start() {
System.out.println("低端引擎转速慢");
}
}
工厂模式之间的对比
- 简单静态工厂模式:虽然不符合设计原则,但用的最多
- 工厂方法模式:可以通过不修改原有类的前提下实现对类的扩展
- 抽象工厂模式:不可以增加单个产品,但可以增加产品族,大项目用的多
代理模式
什么是代理模式
为其他对象提供一种代理以控制对这个对象的访问。
使用情况及优缺点
- 使用情况:想在访问一个类时做一些控制。如安全代理,远程加载,延迟加载
- 优点:职责清晰、高扩展性、智能化。
- 缺点:由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。而且实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
代理模式的例子
静态代理
- 模拟客户找代理买手机
package com.cn.cmc.proxy;
public class StaticProxy {
public static void main(String[] args) {
//模拟客户找代理买一台苹果手机
IPhone iphone = new IPhone() ;
PhoneProxy phoneproxy = new PhoneProxy(iphone) ;
phoneproxy.look();
phoneproxy.tryout();
phoneproxy.consult();
phoneproxy.buy();
phoneproxy.bill();
}
}
/*手机接口*/
interface Phone {
public void look();
public void tryout();
public void consult() ;
public void buy() ;
public void bill() ;
}
/*手机代理类*/
class PhoneProxy implements Phone{
private Phone phone ;
public PhoneProxy(Phone phone) {
super();
this.phone = phone;
}
@Override
public void look() {
System.out.println("代理看手机");
}
@Override
public void tryout() {
System.out.println("代理试用手机");
}
@Override
public void consult() {
System.out.println("代理咨询手机性能");
}
@Override
public void buy() {
phone.buy();
}
@Override
public void bill() {
System.out.println("代理要发票");
}
}
/*手机类*/
class IPhone implements Phone {
@Override
public void look() {
System.out.println("苹果店里看手机");
}
@Override
public void tryout() {
System.out.println("苹果店里试用手机");
}
@Override
public void consult() {
System.out.println("苹果店里咨询手机");
}
@Override
public void buy() {
System.out.println("苹果店里买手机");
}
@Override
public void bill() {
System.out.println("苹果店里要发票");
}
}
动态代理
package com.cn.cmc.proxy;
import java.awt.PageAttributes;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKDynamicProxy {
public static void main(String[] args) {
Phone iphone = new IPhone() ;
PhoneHandler phonehandler = new PhoneHandler(iphone) ;
/*创建一个代理
* classloader:类加载器
* class[]:要代理的Class数组
* handler:代理要实现的Handler
* */
Phone proxy = (Phone) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Phone.class}, phonehandler) ;
proxy.buy();
}
}
/*手机代理类*/
class PhoneHandler implements InvocationHandler{
Phone phone ;
public PhoneHandler(Phone phone) {
super();
this.phone = phone;
}
/**
* invoke为调用真正的方法
* proxy:为在其上调用方法的代理实例
* method:对应于在代理实例上调用的接口方法的 Method 实例
* args:包含传入代理实例上方法调用的参数值的对象数组
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理开始买手机");
if(method.getName().equals("look")){
phone.look();
}else if(method.getName().equals("tryout")){
phone.tryout();
}else if(method.getName().equals("consult")){
phone.consult();
}else if(method.getName().equals("buy")){
phone.buy();
}else if(method.getName().equals("bill")){
phone.bill();
}else{
System.out.println("没有此方法");
}
System.out.println("代理买手机结束");
return null;
}
}
/*手机接口*/
interface Phone {
public void look();
public void tryout();
public void consult() ;
public void buy() ;
public void bill() ;
}
/*手机类*/
class IPhone implements Phone {
@Override
public void look() {
System.out.println("苹果店里看手机");
}
@Override
public void tryout() {
System.out.println("苹果店里试用手机");
}
@Override
public void consult() {
System.out.println("苹果店里咨询手机");
}
@Override
public void buy() {
System.out.println("苹果店里买手机");
}
@Override
public void bill() {
System.out.println("苹果店里要发票");
}
}