最近的项目里面涉及到一些Java设计模式,在此简单谈一下自己的看法,以下示例一部分参考同行,大部分自己设计。
1.单例模式
如果一个类始终只能创建一个实例,则这个类成为单例类,这种设计模式称为单例模式。
class Singleton
{
// 使用一个类变量缓存创建的实例
private static Singleton instance;
// 隐藏构造器
private Singleton(){
}
// 提供一个静态方法,用于返回Singleton实例
public static Singleton getInstance()
{
// 如果instance为null,表明还不曾创建Singleton对象
// 如果instance不为null,则表明已经创建了Singleton对象,将不会执行该方法
if (instance == null)
{
// 创建一个Singleton对象,并将其缓存起来
instance = new Singleton();
}
//如果instance已经创建过,直接返回
return instance;
}
}
写个测试程序
public class SingletonTest
{
public static void main(String[] args)
{
// 创建两个Singleton 对象
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
// 将输出true
System.out.println(s1 == s2);
}
}
Spring容器所管理的Bean实例默认是单例,可以通过scope来修改其行为方式。
使用单例模式的优势:
(1)减少系统开销(不用每次都创建新的实例)
(2)便于系统跟踪单个实例的生命周期与实例状态等。
2.简单工厂
通过工厂来创建对象的设计模式称为简单工厂模式。
当需要创建一个对象的时候不通过new 来创建,而是通过向工厂下订单来创建。
先定义一个房子(House),房子里面有张桌子(Table),还可以获得桌子的相关信息(getTableMaterial()获得桌子的材料)。
/**
*
* 一个House里面有张桌子table(这个table是抽象的,需要工厂根据用户的实际要求具体实现)
* table通过工厂tableFactory来生产
* tableFactory根据用户所要求的材料material来定制table
*/
public class House {
private Table table;
public House(Table table){
this.table = table;
}
//获得table 的material(所用材料)
public void getTableMaterial(){
table.getMaterial();
}
public static void main(String[] args){
TableFactory tableFactory = new TableFactory();
//通过工厂生产Table对象并传递给构造器
House house = new House(tableFactory.getTable("wood"));
house.getTableMaterial();
}
}
下面是Table接口,拥有Table的一般行为。
public interface Table {
public void getMaterial();
}
下面是三个具体的实现类(三种材质的桌子)。
/**
* 木桌
*/
public class WoodTable implements Table {
@Override
public void getMaterial() {
// TODO Auto-generated method stub
System.out.println("Material of this Table is Wood!");
}
}
/**
* 铁桌
*/
public class SteelTable implements Table {
@Override
public void getMaterial() {
// TODO Auto-generated method stub
System.out.println("Material of this Table is Steel!");
}
}
/**
* 塑料桌
*/
public class PlasticTable implements Table {
@Override
public void getMaterial() {
// TODO Auto-generated method stub
System.out.println("Material of this Table is Plastic!");
}
}
下面是桌子工厂,可以根据用户的需求生产相应的桌子。
public class TableFactory {
public Table getTable(String material){
switch(material){
case "wood":
return new WoodTable();
case "steel":
return new SteelTable();
default :
return new PlasticTable();
}
}
}
下面进行测试:
public static void main(String[] args){
TableFactory tableFactory = new TableFactory();
//工厂根据用户的需求生产Table对象并传递给构造器
House house = new House(tableFactory.getTable("wood"));//用户要求木桌(woodTable)
house.getTableMaterial();
}
测试结果:
用户可以向工厂提出自己的需求(woodTable ,steelTable还是plasticTable),由工厂来生产Table(创建Table对象);
简单工厂的优势:对象的调用者与对象的创建过程分离,避免对象的调用与实现以硬编码的方式耦合,提高系统的可维护性和可拓展性。
3.抽象工厂模式
抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。
来看个示例。
有一个汽车商店(CarShop),里面有一辆汽车(car),还可以获得汽车的相关信息。
public class CarShop {
private Car car;
public CarShop(Car car){
this.car = car;
}
//获得汽车的相关信息
public void getCarInfo(){
car.getCarInfo();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//通过抽象工厂获得具体工厂
CarFactory cf = CarFactoryFactory.getCarFactory("A");
//通过具体工厂创建具体car对象并传递给构造器
CarShop cs = new CarShop(cf.createCar("BMW"));
cs.getCarInfo();
}
}
有一个抽象汽车工厂,用来根据用户需求创建具体汽车工厂。
public class CarFactoryFactory {
//根据carType创建具体工厂
public static CarFactory getCarFactory(String carType){
switch(carType){
case "A":
return new ACarFactory();
case "B":
return new BCarFactory();
default :
return new CCarFactory();
}
}
}
有A、B、C三个具体汽车工厂,用来生产三种类型的汽车。
/**
* A工厂
* 根据用户要求的品牌(carBrand)
* 生产A类型的汽车
*/
public class ACarFactory implements CarFactory {
@Override
public Car createCar(String carBrand) {
// TODO Auto-generated method stub
switch(carBrand){
case "BMW":
return new BMWCarA();
case "Benz":
return new BenzCarA();
default :
return new AudiCarA();
}
}
}
/**
* B工厂
* 根据用户要求的品牌(carBrand)
* 生产B类型的汽车
*/
public class BCarFactory implements CarFactory {
/* (non-Javadoc)
* @see com.abstructFactory.CarFactory#createCar(java.lang.String)
*/
@Override
public Car createCar(String carBrand) {
switch(carBrand){
case "BMW":
return new BMWCarB();
case "Benz":
return new BenzCarB();
default :
return new AudiCarB();
}
}
}
/**
* C工厂
* 根据用户要求的品牌(carBrand)
* 生产C类型的汽车
*/
public class CCarFactory implements CarFactory {
@Override
public Car createCar(String carBrand) {
switch(carBrand){
case "BMW":
return new BMWCarC();
case "Benz":
return new BenzCarC();
default :
return new AudiCarC();
}
}
}
这三个具体工厂类都实现了同一个汽车工厂接口,该接口拥有一般汽车工厂的行为。
public interface CarFactory {
public Car createCar(String carBrand);
}
A、B、C三个具体汽车工厂分别生产三种品牌(BMW,Benz和Audi)的汽车。
/**
* A工厂生产的Audi汽车
*/
public class AudiCarA implements Car {
@Override
public void getCarInfo() {
System.out.println("Audi car from ACarFactory");
}
}
/**
* A工厂生产的Benz汽车
*/
public class BenzCarA implements Car {
@Override
public void getCarInfo() {
System.out.println("Benz car from ACarFactory");
}
}
/**
* A工厂生产的BMW汽车
*/
public class BMWCarA implements Car {
@Override
public void getCarInfo() {
System.out.println("BMW car from ACarFactory");
}
}
/**
* B工厂生产的Audi汽车
*/
public class AudiCarB implements Car {
@Override
public void getCarInfo() {
System.out.println("Audi car from BCarFactory");
}
}
/**
* B工厂生产的Benz汽车
*/
public class BenzCarB implements Car {
@Override
public void getCarInfo() {
System.out.println("Benz car from BCarFactory");
}
}
/**
* B工厂生产的BMW汽车
*/
public class BMWCarB implements Car {
@Override
public void getCarInfo() {
System.out.println("BMW car from BCarFactory");
}
}
/**
* C工厂生产的Audi汽车
*/
public class AudiCarC implements Car {
@Override
public void getCarInfo() {
System.out.println("BMW car from CCarFactory");
}
}
/**
* C工厂生产的Benz汽车
*/
public class BenzCarC implements Car {
@Override
public void getCarInfo() {
System.out.println("BMW car from CCarFactory");
}
}
/**
* C工厂生产的BMW汽车
*/
public class BMWCarC implements Car {
@Override
public void getCarInfo() {
System.out.println("BMW car from CCarFactory");
}
}
这些具体的汽车产品都实现了同一个接口(Car),该接口拥有汽车的一般行为。
public interface Car {
public void getCarInfo();
}
下面来做个测试,用户要求一辆A工厂生产的BMW汽车:
public static void main(String[] args) {
// TODO Auto-generated method stub
//通过抽象工厂获得具体工厂
CarFactory cf = CarFactoryFactory.getCarFactory("A");
//通过具体工厂创建具体car对象并传递给构造器
CarShop cs = new CarShop(cf.createCar("BMW"));
cs.getCarInfo();
}
测试结果:
抽象工厂可以根据用户的需求,通过不同的具体工厂生产不同的产品。
那么抽象工厂模式有什么好处呢?假如采用简单工厂模式,假如只有A工厂,当用户要求一辆B类型的BMW时,就要修改A工厂代码来生产BMWCarB对象。所以,抽象工厂模式的优势是:对象的调用者与对象的实现类以及具体的工厂分离,代码的耦合性更低,系统可维护性以及可拓展性更高。
但是抽象工厂模式有个缺陷,就是当用户需求改变的时候,需要修改代码,然后需要重新编译,最好是将用户需求(可以看做用户订单)放在一个配置文件里面,由代码根据配置文件来创建相应的工厂以及实例,这样当用户需求发生改变的时候,只需要修改配置文件(产品订单)即可。
Spring IOC容器是一个抽象工厂,既可以管理Bean实例,还可以管理工厂实例。ApplicationContext.xml可以看作是系统的订单,容器根据这个订单生产相应的Bean。
4.观察者模式
观察者模式又称发布订阅模式,定义了一种一对多依赖关系,让一个或多个观察者对象观察一个主题对象,当主题对象的状态发生改变时,系统会通知所有的依赖于此对象的观察者,从而使得观察者对象能够自动更新。
看一个示例:
有一个任务列表TaskList,里面的任务需要两个程序员去完成,TaskList可以看作是被观察的主题对象,两个程序员可以看作是依赖于此主题对象的观察者,当任务列表里面的任务更新时,要通知这两个程序员。
下面是TaskList:
public class TaskList extends Observable{
private List allTask;
private static TaskList instance;
//私有构造器
private TaskList(){
}
public static TaskList getInstance(){
if(instance == null){
instance = new TaskList();
instance.allTask = new ArrayList();
}
return instance;
}
//添加观察者
public void addTaskObserver(Observer observer){
this.addObserver(observer);
}
//任务列表发生改变
public void addNewTask(String newTask){
allTask.add("new Task");
System.out.println("系统添加了新任务");
//被观察对象发生改变
this.setChanged();
//通知观察者并传递新任务
this.notifyObservers(newTask);
}
}
下面是两个程序员:
public class ProgrammerA implements Observer{
//自动更新
@Override
public void update(Observable o, Object task) {
String newTask = (String)task;
System.out.println("ProgrammerA 您有新的任务: " +newTask);
}
}
public class ProgrammerB implements Observer{
//自动更新
@Override
public void update(Observable o, Object task) {
String newTask = (String)task;
System.out.println("ProgrammerB 您有新的任务: " +newTask);
}
}
下面做个测试:
public class ObserverTest {
public static void main(String[] args) {
//被观察的任务列表
TaskList observable = TaskList.getInstance();
//观察者
ProgrammerA pa = new ProgrammerA();
ProgrammerB pb = new ProgrammerB();
//添加观察者
observable.addObserver(pa);
observable.addObserver(pb);
//任务列表发生改变
observable.addNewTask("new Task");
}
}
Java EE 应用中,主题/订阅模式下的JMS就是观察者模式的应用。
设计模式是对处于特定环境下,经常出现的某类软件开发问题的一种相对成熟的设计方案,是软件设计师集体经验的体现。优雅的代码没必要刻意使用哪种设计模式,最好是它本身就体现出设计模式。