不要为了用设计模式而用设计模式
2014-06-12 16:59
274 查看
近来准备从通讯设备行业中面向业务,面向流程的开发模式转型,去拥抱OOD/OOP,拥抱互联网。要学习面向对象设计,必然要面对的软件灵活性,复用性的问题。而解决这一问题的快速方式是采用合适的设计模式去增强软件的灵活性和复用性。
Christopher Alexander说过“每一个设计模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动”
设计模式,给我们带来以下便利:
设计模式使人们可以更加简单方便地复用成功的设计和体系结构。
将已证明的技术表述成设计模式也会使新系统开发者更容易理解其设计思路。
设计模式帮助你做出有利于系统复用的选择,避免设计损害系统的复用性。
通过提供一个显式类和对象作用关系以及他们之间的潜在联系的说明规范,设计模式可以提高已有系统的文档管理和系统维护的有效性
但在学习设计模式的过程中的一个明显误区是,我们记住了设计模式的形态,却不了解设计模式在什么地方解决问题。就好比学了降龙十八掌的招式,却不知道在什么情况下该出什么招。
以下,是我在学习过程中看到的一个例子:
----------------------------------------------------------例子----------------------------------------------------------
【3】如何用java语言来实现该模式
背景:用一个分别对不同数据库(Oracle 或 SQL Server)中表( User 和 Department )的操作的实例来展示该设计模式。先看下代码的结构图:
3.1 首先定义两个抽象的产品类:IUser.java 和 IDepartment.java。
IUser.java的源码:
[html] view
plaincopy
package com.andyidea.patterns.abstractproduct;
/**
* 抽象产品角色:User接口
* @author Andy.Chen
*
*/
public interface IUser {
}
IDepartment.java源码:
[html] view
plaincopy
package com.andyidea.patterns.abstractproduct;
/**
* 抽象产品角色:Department接口
* @author Andy.Chen
*
*/
public interface IDepartment {
}
3.2 定义抽象工厂类:IDBFactory.java
[html] view
plaincopy
package com.andyidea.patterns.abstractfactory;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
/**
* 抽象工厂角色:工厂接口
* @author Andy.Chen
*
*/
public interface IDBFactory {
public IUser createUser();
public IDepartment createDepartment();
}
3.3创建具体产品角色类:OracleOfUser.java;OracleOfDepartment.java;SQLServerOfUser.java;SQLServerOfDepartment.java。分别继承IUser.java和IDepartment.java。
OracleOfUser.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IUser;
/**
* 具体产品角色:Oracle中的User
* @author Andy.Chen
*
*/
public class OracleOfUser implements IUser{
public OracleOfUser(){
System.out.println("Oracle工厂:在Oracle中操作User表.");
}
}
OracleOfDepartment.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IDepartment;
/**
* 具体产品角色:Oracle中的Department
* @author Andy.Chen
*
*/
public class OracleOfDepartment implements IDepartment{
public OracleOfDepartment(){
System.out.println("Oracle工厂:在Oracle中操作Department表.");
}
}
SQLServerOfUser.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IUser;
/**
* 具体产品角色:SQL Server中的User
* @author Andy.Chen
*
*/
public class SQLServerOfUser implements IUser{
public SQLServerOfUser(){
System.out.println("SQL Server工厂:在SQL Server中操作User表.");
}
}
SQLServerOfDepartment.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IDepartment;
/**
* 具体产品角色:SQL Server中的Department
* @author Andy.Chen
*
*/
public class SQLServerOfDepartment implements IDepartment{
public SQLServerOfDepartment(){
System.out.println("SQL Server工厂:在SQL Server中操作Department表.");
}
}
3.4 创建具体工厂类:OracleFactory.java和SQLServerFactory.java。
OracleFactory.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concretefactory;
import com.andyidea.patterns.abstractfactory.IDBFactory;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
import com.andyidea.patterns.concreteproduct.OracleOfDepartment;
import com.andyidea.patterns.concreteproduct.OracleOfUser;
/**
* 具体工厂角色:Oracle工厂
* @author Andy.Chen
*
*/
public class OracleFactory implements IDBFactory{
@Override
public IUser createUser() {
return new OracleOfUser();
}
@Override
public IDepartment createDepartment() {
return new OracleOfDepartment();
}
}
SQLServerFactory.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concretefactory;
import com.andyidea.patterns.abstractfactory.IDBFactory;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
import com.andyidea.patterns.concreteproduct.SQLServerOfDepartment;
import com.andyidea.patterns.concreteproduct.SQLServerOfUser;
/**
* 具体工厂角色:SQL Server工厂
* @author Andy.Chen
*
*/
public class SQLServerFactory implements IDBFactory{
@Override
public IUser createUser() {
return new SQLServerOfUser();
}
@Override
public IDepartment createDepartment() {
return new SQLServerOfDepartment();
}
}
3.5 客户端测试类:AbstractFactoryClient.java
[html] view
plaincopy
package com.andyidea.patterns.client;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
import com.andyidea.patterns.concretefactory.OracleFactory;
import com.andyidea.patterns.concretefactory.SQLServerFactory;
/**
* 抽象工厂测试类
* @author Andy.Chen
*
*/
public class AbstractFactoryClient {
public static void main(String[] args) {
System.out.println("Welcome to Andy.Chen Blog!" +"\n"
+"Abstract Factory Patterns." +"\n"
+"-------------------------------");
IUser oracleUser,sqlUser;
IDepartment oracleDept,sqlDept;
OracleFactory of = new OracleFactory();
SQLServerFactory sf = new SQLServerFactory();
oracleUser = of.createUser();
oracleDept = of.createDepartment();
sqlUser = sf.createUser();
sqlDept = sf.createDepartment();
}
}
【4】程序运行结果:
public class AbstractFactoryClient {
public static void main(String[] args) {
IUser oracleUser,sqlUser;
IDepartment oracleDept,sqlDept;
OracleFactory of = new OracleFactory();
SQLServerFactory sf = new SQLServerFactory();
oracleUser = of.createUser();
oracleDept = of.createDepartment();
sqlUser = sf.createUser();
sqlDept = sf.createDepartment();
}
}
[html] view
plaincopy
Welcome to Andy.Chen Blog!
Abstract Factory Patterns.
-------------------------------
Oracle工厂:在Oracle中操作User表.
Oracle工厂:在Oracle中操作Department表.
SQL Server工厂:在SQL Server中操作User表.
SQL Server工厂:在SQL Server中操作Department表.
----------------------------------------------------------例子结束----------------------------------------------------------
可以看到,在例子中,作者正确的按照了AbstractFactory的方式定义了AbstractFactory类,ConcreteFactory类,AbstractProduct类和ConcreteProduct类。但却没有完全明白AbstractFactory模式解决的是哪类复用问题,在什么情况下被使用。
AbstractFactory接口确定了可以被创建的产品的集合。使用AbstractFactory,使得我们易于交换产品系列。有利于产品的一致性。
在这段client代码中,系统的作用被定义为创建所有产品,这里并不存在说我们要复用这段代码,因为所有定义在AbstractFactory产品已经被创建出来,它已经使“复用代码,使设计易于交换产品系列”这个命题失效。因此,在这种情况下套用AbstractFactory模式,并没有得到我们想要的效果。
正确的使用场景应该是AbstractFactoryClient用于创建用户数据,并且该用户数据可能存储在不同的数据库系统中,为了使AbstractFactoryClient可以针对不同的数据库系统复用同一段代码,我们才考虑去采用AbstractFactory模式。
当client代码写成如下模式的时候我们才考虑用AbstractFactory模式去优化它:
public class AbstractFactoryClient {
public static void main(String[] args) {
SQLOfUser user = new SQLOfUser();
SQLServerOfDepartment Dept = new SQLServerOfDepartment();
}
}
AbstractFactoryClient用createData去创建它需要的数据,并且创建的过程是调用了虚(abstract)函数(interface),使得这段代码可以被复用,随时根据所需去改变实例化的类,替换Product。
public class AbstractFactoryClient {
public static void main(String[] args) {
IUser user;
IDepartment dept;
//用户根据产品类型,复用一下代码
IDBFactoryfactory
= new SQLFactory(); //or new oracleFactory()
CreateData(factory);
}
public CreateData(IDBFactory factory){
user = Factory.createUser();
Dept = Factroy.createDepartment();
)
}
总结:在使用设计模式之前,一定要搞清楚我们的问题是什么,选用的设计模式使解决什么样的特定设计问题。作者最原始的代码没有问题,但如果我们没有client端去看为什么要使用这种设计模式时,我们就很容易走入为使用设计模式而使用设计模式的误区。要记住,设计模式永远是为了让你的软件更具灵活性和复用性,而不是让你代码看起来很漂亮,用了很多设计模式!
Christopher Alexander说过“每一个设计模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动”
设计模式,给我们带来以下便利:
设计模式使人们可以更加简单方便地复用成功的设计和体系结构。
将已证明的技术表述成设计模式也会使新系统开发者更容易理解其设计思路。
设计模式帮助你做出有利于系统复用的选择,避免设计损害系统的复用性。
通过提供一个显式类和对象作用关系以及他们之间的潜在联系的说明规范,设计模式可以提高已有系统的文档管理和系统维护的有效性
但在学习设计模式的过程中的一个明显误区是,我们记住了设计模式的形态,却不了解设计模式在什么地方解决问题。就好比学了降龙十八掌的招式,却不知道在什么情况下该出什么招。
以下,是我在学习过程中看到的一个例子:
----------------------------------------------------------例子----------------------------------------------------------
【3】如何用java语言来实现该模式
背景:用一个分别对不同数据库(Oracle 或 SQL Server)中表( User 和 Department )的操作的实例来展示该设计模式。先看下代码的结构图:
3.1 首先定义两个抽象的产品类:IUser.java 和 IDepartment.java。
IUser.java的源码:
[html] view
plaincopy
package com.andyidea.patterns.abstractproduct;
/**
* 抽象产品角色:User接口
* @author Andy.Chen
*
*/
public interface IUser {
}
IDepartment.java源码:
[html] view
plaincopy
package com.andyidea.patterns.abstractproduct;
/**
* 抽象产品角色:Department接口
* @author Andy.Chen
*
*/
public interface IDepartment {
}
3.2 定义抽象工厂类:IDBFactory.java
[html] view
plaincopy
package com.andyidea.patterns.abstractfactory;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
/**
* 抽象工厂角色:工厂接口
* @author Andy.Chen
*
*/
public interface IDBFactory {
public IUser createUser();
public IDepartment createDepartment();
}
3.3创建具体产品角色类:OracleOfUser.java;OracleOfDepartment.java;SQLServerOfUser.java;SQLServerOfDepartment.java。分别继承IUser.java和IDepartment.java。
OracleOfUser.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IUser;
/**
* 具体产品角色:Oracle中的User
* @author Andy.Chen
*
*/
public class OracleOfUser implements IUser{
public OracleOfUser(){
System.out.println("Oracle工厂:在Oracle中操作User表.");
}
}
OracleOfDepartment.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IDepartment;
/**
* 具体产品角色:Oracle中的Department
* @author Andy.Chen
*
*/
public class OracleOfDepartment implements IDepartment{
public OracleOfDepartment(){
System.out.println("Oracle工厂:在Oracle中操作Department表.");
}
}
SQLServerOfUser.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IUser;
/**
* 具体产品角色:SQL Server中的User
* @author Andy.Chen
*
*/
public class SQLServerOfUser implements IUser{
public SQLServerOfUser(){
System.out.println("SQL Server工厂:在SQL Server中操作User表.");
}
}
SQLServerOfDepartment.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concreteproduct;
import com.andyidea.patterns.abstractproduct.IDepartment;
/**
* 具体产品角色:SQL Server中的Department
* @author Andy.Chen
*
*/
public class SQLServerOfDepartment implements IDepartment{
public SQLServerOfDepartment(){
System.out.println("SQL Server工厂:在SQL Server中操作Department表.");
}
}
3.4 创建具体工厂类:OracleFactory.java和SQLServerFactory.java。
OracleFactory.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concretefactory;
import com.andyidea.patterns.abstractfactory.IDBFactory;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
import com.andyidea.patterns.concreteproduct.OracleOfDepartment;
import com.andyidea.patterns.concreteproduct.OracleOfUser;
/**
* 具体工厂角色:Oracle工厂
* @author Andy.Chen
*
*/
public class OracleFactory implements IDBFactory{
@Override
public IUser createUser() {
return new OracleOfUser();
}
@Override
public IDepartment createDepartment() {
return new OracleOfDepartment();
}
}
SQLServerFactory.java源码:
[html] view
plaincopy
package com.andyidea.patterns.concretefactory;
import com.andyidea.patterns.abstractfactory.IDBFactory;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
import com.andyidea.patterns.concreteproduct.SQLServerOfDepartment;
import com.andyidea.patterns.concreteproduct.SQLServerOfUser;
/**
* 具体工厂角色:SQL Server工厂
* @author Andy.Chen
*
*/
public class SQLServerFactory implements IDBFactory{
@Override
public IUser createUser() {
return new SQLServerOfUser();
}
@Override
public IDepartment createDepartment() {
return new SQLServerOfDepartment();
}
}
3.5 客户端测试类:AbstractFactoryClient.java
[html] view
plaincopy
package com.andyidea.patterns.client;
import com.andyidea.patterns.abstractproduct.IDepartment;
import com.andyidea.patterns.abstractproduct.IUser;
import com.andyidea.patterns.concretefactory.OracleFactory;
import com.andyidea.patterns.concretefactory.SQLServerFactory;
/**
* 抽象工厂测试类
* @author Andy.Chen
*
*/
public class AbstractFactoryClient {
public static void main(String[] args) {
System.out.println("Welcome to Andy.Chen Blog!" +"\n"
+"Abstract Factory Patterns." +"\n"
+"-------------------------------");
IUser oracleUser,sqlUser;
IDepartment oracleDept,sqlDept;
OracleFactory of = new OracleFactory();
SQLServerFactory sf = new SQLServerFactory();
oracleUser = of.createUser();
oracleDept = of.createDepartment();
sqlUser = sf.createUser();
sqlDept = sf.createDepartment();
}
}
【4】程序运行结果:
public class AbstractFactoryClient {
public static void main(String[] args) {
IUser oracleUser,sqlUser;
IDepartment oracleDept,sqlDept;
OracleFactory of = new OracleFactory();
SQLServerFactory sf = new SQLServerFactory();
oracleUser = of.createUser();
oracleDept = of.createDepartment();
sqlUser = sf.createUser();
sqlDept = sf.createDepartment();
}
}
[html] view
plaincopy
Welcome to Andy.Chen Blog!
Abstract Factory Patterns.
-------------------------------
Oracle工厂:在Oracle中操作User表.
Oracle工厂:在Oracle中操作Department表.
SQL Server工厂:在SQL Server中操作User表.
SQL Server工厂:在SQL Server中操作Department表.
----------------------------------------------------------例子结束----------------------------------------------------------
可以看到,在例子中,作者正确的按照了AbstractFactory的方式定义了AbstractFactory类,ConcreteFactory类,AbstractProduct类和ConcreteProduct类。但却没有完全明白AbstractFactory模式解决的是哪类复用问题,在什么情况下被使用。
AbstractFactory接口确定了可以被创建的产品的集合。使用AbstractFactory,使得我们易于交换产品系列。有利于产品的一致性。
在这段client代码中,系统的作用被定义为创建所有产品,这里并不存在说我们要复用这段代码,因为所有定义在AbstractFactory产品已经被创建出来,它已经使“复用代码,使设计易于交换产品系列”这个命题失效。因此,在这种情况下套用AbstractFactory模式,并没有得到我们想要的效果。
正确的使用场景应该是AbstractFactoryClient用于创建用户数据,并且该用户数据可能存储在不同的数据库系统中,为了使AbstractFactoryClient可以针对不同的数据库系统复用同一段代码,我们才考虑去采用AbstractFactory模式。
当client代码写成如下模式的时候我们才考虑用AbstractFactory模式去优化它:
public class AbstractFactoryClient {
public static void main(String[] args) {
SQLOfUser user = new SQLOfUser();
SQLServerOfDepartment Dept = new SQLServerOfDepartment();
}
}
AbstractFactoryClient用createData去创建它需要的数据,并且创建的过程是调用了虚(abstract)函数(interface),使得这段代码可以被复用,随时根据所需去改变实例化的类,替换Product。
public class AbstractFactoryClient {
public static void main(String[] args) {
IUser user;
IDepartment dept;
//用户根据产品类型,复用一下代码
IDBFactoryfactory
= new SQLFactory(); //or new oracleFactory()
CreateData(factory);
}
public CreateData(IDBFactory factory){
user = Factory.createUser();
Dept = Factroy.createDepartment();
)
}
总结:在使用设计模式之前,一定要搞清楚我们的问题是什么,选用的设计模式使解决什么样的特定设计问题。作者最原始的代码没有问题,但如果我们没有client端去看为什么要使用这种设计模式时,我们就很容易走入为使用设计模式而使用设计模式的误区。要记住,设计模式永远是为了让你的软件更具灵活性和复用性,而不是让你代码看起来很漂亮,用了很多设计模式!
相关文章推荐
- NDatabase 入门,简单使用 增删改查。让NDatabase带你脱离ADO.net,各种SQL 语句,各种DBMS,各种CRM,IOC之类的烦恼。我们也不需要仓库设计模式了,你妹的。不要表了,不要设计数据库字段了。就这样!
- 请不要滥用设计模式——SingleTon篇
- 【设计模式】外观模式——“知道有它就行了,内容不要你懂。”
- [转贴] 不要以为使用了模式就是好设计
- 设计模式之25: 奥运金牌第一加老百姓买什么都不放心加为了一时的蓝天要把进京的各种车辆卡掉加奥运动员食品要专供模式
- 不要设计模式
- 设计模式开篇-不要滥用设计模式
- 不要老谈“设计模式”
- [转贴] 不要以为使用了模式就是好设计
- 不要使用不理解或不适用的架构或设计模式
- 设计原则:不要为了复用而使用继承
- 怎么做产品设计师-不要为了设计而设计
- 要想正确理解设计模式,首先必须明确它是为了解决什么问题而提出来的。
- 转载---23种设计模式(场景需要决定使用模式,非为了用而用)
- 好书系列之-设计模式:可复用面向对象软件的基础 1
- 好书整理系列之-设计模式:可复用面向对象软件的基础 2
- 设计模式、用Delphi描述-->Abstract Factory模式
- 好书整理系列之-设计模式:可复用面向对象软件的基础 3
- 好书整理系列之-设计模式:可复用面向对象软件的基础 4
- 设计模式、用Delphi描述-->Factory Method模式