栗のために
問題の説明
シミュレーションデータベースへのアクセスは、「ユーザーの追加」および「ユーザーを取得する」、と仮定している唯一のユーザクラスIDと名前二つのフィールド。
単純な実装
ユーザー
/**
* 用户类
* Created by callmeDevil on 2019/7/28.
*/
public class User {
private int id;
private String name;
// 省略 get set 方法
}
SqlServerUser
/**
* 假设sqlServer 连接,用于操作User表
* Created by callmeDevil on 2019/7/28.
*/
public class SqlServerUser {
public void insert(User user){
System.out.println("在SQL Server中给User表增加一条记录");
}
public User getUser(int id){
System.out.println("在SQL Server中根据ID得到User表一条记录");
return null;
}
}
テスト
public class Test {
public static void main(String[] args) {
User user = new User();
SqlServerUser su = new SqlServerUser();
su.insert(user);
su.getUser(user.getId());
}
}
テスト結果
在SQL Server中给User表增加一条记录
在SQL Server中根据ID得到User表一条记录
問題があります
あなたが他のデータベースに接続する必要がある場合は、この文言は、以下の使用して、拡大することはできませんFactory Methodパターンを達成するために
Factory Methodパターンの実装
iuseris
/**
* 用于客户端访问,解除与具体数据库访问的耦合
* Created by callmeDevil on 2019/7/28.
*/
public interface IUser {
void insert(User user);
User getUser(int id);
}
SqlServerUser
/**
* 用于访问SQL Server 的User
* Created by callmeDevil on 2019/7/28.
*/
public class SqlServerUser implements IUser {
@Override
public void insert(User user) {
System.out.println("在SQL Server中给User表增加一条记录");
}
@Override
public User getUser(int id) {
System.out.println("在SQL Server中根据ID得到User表一条记录");
return null;
}
}
AccessUser
/**
* 用于访问Access 的User
* Created by callmeDevil on 2019/7/28.
*/
public class AccessUser implements IUser {
@Override
public void insert(User user) {
System.out.println("在Access 中给User表增加一条记录");
}
@Override
public User getUser(int id) {
System.out.println("在在Access中根据ID得到User表一条记录");
return null;
}
}
IFactoryです
/**
* 定义一个创建访问User 表对象的抽象工厂接口
* Created by callmeDevil on 2019/7/28.
*/
public interface IFactory {
IUser createUser();
}
SqlServerFactory
/**
* 实现IFactory 接口,实例化SQLServerUser
* Created by callmeDevil on 2019/7/28.
*/
public class SqlServerFactory implements IFactory {
@Override
public IUser createUser() {
return new SqlServerUser();
}
}
AccessFactory
/**
* 实现IFactory 接口,实例化AccessUser
* Created by callmeDevil on 2019/7/28.
*/
public class AccessFactory implements IFactory {
@Override
public IUser createUser() {
return new AccessUser();
}
}
テスト
public class Test {
public static void main(String[] args) {
User user = new User();
// 若要更改成 Access 数据库,只需要将此处改成
// IFactory factory = new AccessFactory();
IFactory factory = new SqlServerFactory();
IUser iUser = factory.createUser();
iUser.insert(user);
iUser.getUser(1);
}
}
以上の試験結果。
需要の増加
あなたは、テーブル部門(部門)を追加したい場合は、どのように変更する必要がありますか?
実装を変更します。
部門
/**
* 部门表
* Created by callmeDevil on 2019/7/28.
*/
public class Department {
private int id;
private String name;
// 省略 get set 方法
}
IDepartment
/**
* 用于客户端访问,解除与具体数据库访问的耦合
* Created by callmeDevil on 2019/7/28.
*/
public interface IDepartment {
void insert(Department department);
Department getDepartment(int id);
}
SqlServerDepartment
/**
* 用于访问SqlServer 的Department
* Created by callmeDevil on 2019/7/28.
*/
public class SqlServerDepartment implements IDepartment {
@Override
public void insert(Department department) {
System.out.println("在 SqlServer 中给Department 表增加一条记录");
}
@Override
public Department getDepartment(int id) {
System.out.println("在SQL Server中根据ID得到Department表一条记录");
return null;
}
}
AccessDepartment
/**
* 用于访问Access 的Department
* Created by callmeDevil on 2019/7/28.
*/
public class AccessDepartment implements IDepartment {
@Override
public void insert(Department department) {
System.out.println("在Access 中给Department 表增加一条记录");
}
@Override
public Department getDepartment(int id) {
System.out.println("在Access 中根据ID得到Department表一条记录");
return null;
}
}
IFactoryです
/**
* 定义一个创建访问User 表对象的抽象工厂接口
* Created by callmeDevil on 2019/7/28.
*/
public interface IFactory {
IUser createUser();
IDepartment createDepartment(); //增加的接口方法
}
SqlServerFactory
/**
* 实现IFactory 接口,实例化SQLServerUser
* Created by callmeDevil on 2019/7/28.
*/
public class SqlServerFactory implements IFactory {
@Override
public IUser createUser() {
return new SqlServerUser();
}
@Override
public IDepartment createDepartment() {
return new SqlServerDepartment(); //增加了SqlServerDepartment 工厂
}
}
AccessFactory
/**
* 实现IFactory 接口,实例化AccessUser
* Created by callmeDevil on 2019/7/28.
*/
public class AccessFactory implements IFactory {
@Override
public IUser createUser() {
return new AccessUser();
}
@Override
public IDepartment createDepartment() {
return new AccessDepartment(); //增加了AccessDepartment 工厂
}
}
テスト
public class Test {
public static void main(String[] args) {
User user = new User();
Department dept = new Department();
// 只需确定实例化哪一个数据库访问对象给 factory
IFactory factory = new AccessFactory();
// 则此时已于具体的数据库访问解除了依赖
IUser iUser = factory.createUser();
iUser.insert(user);
iUser.getUser(1);
IDepartment iDept = factory.createDepartment();
iDept.insert(dept);
iDept.getDepartment(1);
}
}
テスト結果
在Access 中给User表增加一条记录
在Access 中根据ID得到User表一条记录
在Access 中给Department 表增加一条记录
在Access 中根据ID得到Department表一条记录
Abstract Factoryパターン
定義
その具象クラスを指定せずに、関連または依存オブジェクトインターフェイスのシリーズを作成します。
UMLダイアグラム
コードの実装
実際に変更が満たされている上に実現Abstract Factoryパターンの実装で、ここには例を。
長所と短所
利点
- 最大の利点は、あなただけのコンクリート工場を変更するアプリケーションを作る時、1つのアプリケーションでは、初期化時に表示する必要があるため、別の具体的なファクトリクラスに、ポートフォリオの切り替えを簡単に非常に簡単になってきた、それだけで、具体的な工場を変更する必要がありますあなたは、さまざまな製品構成を使用することができます。
- これは、クライアントが自分の抽象インタフェースを介してのインスタンスを操作している、別のクライアントの中に具体的な例を作成することができ、特定の製品のクラス名は、特定の分離プラントでは、クライアントコードには表示されません。
短所
あなたはまた、項目のリスト(プロジェクト)へのアクセスを追加した場合は、必要が3クラス、高めるためにさらにiProject、SQLServerProject、AccessProjectをも変更する必要がある、AccessFactoryはIFactoryです、ISQLServerFactoryを、それはあまりにも悪いですが、初めて完全に把握することができます。プログラミングは芸術であり、明らかに変化のように大量の、非常に醜い練習。
工場を改善するためのシンプルな抽象工場
削除IFactoryですザ・、SQLServerFactory、AccessFactoryをし、DATAACCESS、工場を達成するための単純なモデル。
Structureチャート
コードの実装
データアクセス
/**
* 统一管理数据库访问
* Created by callmeDevil on 2019/7/28.
*/
public class DataAccess {
// 数据库名称,可替换成 Access
private static final String DB = "SqlServer";
// private static final String DB = "Access";
public static IUser createUser() {
IUser user = null;
switch (DB) {
case "SqlServer":
user = new SqlServerUser();
break;
case "Access":
user = new AccessUser();
break;
default:
break;
}
return user;
}
public static IDepartment createDepartment() {
IDepartment department = null;
switch (DB) {
case "SqlServer":
department = new SqlServerDepartment();
break;
case "Access":
department = new AccessDepartment();
break;
default:
break;
}
return department;
}
}
テスト
public class Test {
public static void main(String[] args) {
User user = new User();
Department dept = new Department();
// 直接得到实际的数据库访问实例,而不存在任何的依赖
IUser iUser = DataAccess.createUser();
iUser.insert(user);
iUser.getUser(1);
IDepartment iDept = DataAccess.createDepartment();
iDept.insert(dept);
iDept.getDepartment(1);
}
}
テスト結果
在SQL Server中给User表增加一条记录
在SQL Server中根据ID得到User表一条记录
在SQL Server中给Department 表增加一条记录
在SQL Server中根据ID得到Department表一条记录
問題があります
解決しながら、Abstract Factoryパターン問題の多くの部分を修正するために、それらに戻ったシンプルなファクトリパターン問題の始まりは、接続したい場合ということであるのOracleデータベースを、あなたは場所を変更する必要があるDATAACCESSすべてのメソッドは、クラスswicthでプラスケースの枝。
+ +抽象工場実装反射プロファイル
プロファイル(db.properties)
# 数据库名称,可更改成 Access
db=SqlServer
データアクセス
/**
* 统一管理数据库访问
* Created by callmeDevil on 2019/7/28.
*/
public class DataAccess {
// 数据库名称,从配置文件中获取
private static String DB;
public static IUser createUser() throws Exception {
if (DB == null || DB.trim() == "") {
return null;
}
// 拼接具体数据库访问类的权限定名
String className = "com.xxx." + DB + "User";
return (IUser) Class.forName(className).newInstance();
}
public static IDepartment createDeptment() throws Exception {
if (DB == null || DB.trim() == "") {
return null;
}
// 拼接具体数据库访问类的权限定名
String className = "com.xxx." + DB + "Department";
return (IDepartment) Class.forName(className).newInstance();
}
public static String getDB() {
return DB;
}
public static void setDB(String DB) {
DataAccess.DB = DB;
}
}
テスト
public class Test {
public static void main(String[] args) throws Exception {
// 加载配置文件
Properties properties = new Properties();
InputStream is = new FileInputStream(new File("xxx\\db.properties")); // 配置文件所在路径,当前方式采用绝对路径获取
properties.load(is);
is.close();
String db = properties.getProperty("db");
// 使用具体的数据库告诉管理类
DataAccess dataAccess = new DataAccess();
dataAccess.setDB(db);
User user = new User();
IUser iUser = dataAccess.createUser();
iUser.insert(user);
iUser.getUser(1);
Department dept = new Department();
IDepartment iDept = dataAccess.createDeptment();
iDept.insert(dept);
iDept.getDepartment(1);
}
}
テスト結果
在SQL Server中给User表增加一条记录
在SQL Server中根据ID得到User表一条记录
在SQL Server中给Department 表增加一条记录
在SQL Server中根据ID得到Department表一条记录
现在如果我们增加了 Oracle 数据库访问,相关类的增加是不可避免的,这点无论用任何办法都解决不了,不过这叫扩展,开放-封闭原则告诉我们,对于扩展,我们开放,但对于修改,我们应该尽量关闭,就目前实现方式而言,只需要将配置文件中改为 Oracle (如果新增的具体访问类名称为 OracleUser 和 OracleDepartment 的话)即可达到目的,客户端也不需要任何修改。
反射的好处
所有在用简单工厂的地方,都可以考虑用反射技术来去除 switch 或 if,解除分支判断带来的耦合。
总结
可以发现到目前为止,就“工厂”而言,已经包含了三种设计模式:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
对上述模式的不同点将在后续推出,本文篇幅已经过长,此处先不叙述。