デザインパターンのノート(XII)のAbstract Factoryパターンを横たわります

栗のために

問題の説明

シミュレーションデータベースへのアクセスは、「ユーザーの追加」および「ユーザーを取得する」、と仮定している唯一のユーザクラス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 (如果新增的具体访问类名称为 OracleUserOracleDepartment 的话)即可达到目的,客户端也不需要任何修改。

反射的好处

所有在用简单工厂的地方,都可以考虑用反射技术来去除 switch 或 if,解除分支判断带来的耦合。

总结

可以发现到目前为止,就“工厂”而言,已经包含了三种设计模式:

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

对上述模式的不同点将在后续推出,本文篇幅已经过长,此处先不叙述。

おすすめ

転載: www.cnblogs.com/call-me-devil/p/11259982.html