数据源架构模式 表入口 行入口 活动记录 数据映射器

数据源架构模式 - 表入口模式

表入口模式充当数据库表访问入口的对象,一个实例处理表中的所有行。

可以理解为对之前分散在各个页面的sql语句进行封装,一张表就是一个对象,该对象处理所有与该表有关的业务逻辑,很好的提高了代码的复用性。

现在想起来,当初刚毕业那会儿,经常使用表入口模式。

具体的实现方式参见代码:

database.php

<?php   
class Database{  
    //只是为了演示,通常情况下数据库的配置是会单独写在配置文件中的  
    private static $_dbConfig = array(  
        'host' => '127.0.0.1',  
        'username' => 'root',  
        'pwd' => '',  
        'dbname' => 'bussiness'  
        );  
  
    private static $_instance;  
  
    public static function getInstance(){  
        if(is_null(self::$_instance)){  
            self::$_instance = new mysqli(self::$_dbConfig['host'], self::$_dbConfig['username'], self::$_dbConfig['pwd'], self::$_dbConfig['dbname']);   
            if(self::$_instance->connect_errno){  
                throw new Exception(self::$_instance->connect_error);  
            }  
        }  
        return self::$_instance;  
    }  
  
  
}

person.php

<?php   
require_once 'database.php';  
class Person extends Database{  
  
    public $instance;  
  
    public $table = 'person';  
  
    public function __construct(){  
        $this->instance = Person::getInstance();  
    }  
  
    public function getPersonById($personId){  
        $sql = "select * from $this->table where id=$personId";  
        echo $sql;  
        return $this->instance->query($sql);  
    }  
  
    /**其他的一些增删改查操作方法...**/  
}

index.php

<?php   
require_once 'person.php';  
  
$person = new Person();  
var_dump($person->getPersonById(1)->fetch_assoc());  
die();

运行结果:

select * from person where id=1  
array (size=2)  
  'id' => string '1' (length=1)  
  'name' => string 'ben' (length=3) 
 
 
数据源架构模式 - 行入口模式

一、概念

行数据入口(Row Data Gateway):充当数据源中单条记录入口的对象,每行一个实例。

二、简单实现行数据入口

为了方便理解,还是先简单实现:

<?php
 
/**
 * 企业应用架构 数据源架构模式之行数据入口 2010-09-27 sz
 * @author phppan.p#gmail.com  http://www.phppan.com
 * 哥学社成员(http://www.blog-brother.com/)
 * @package architecture
 */
class PersonGateway {
 
    private $_name;
    private $_id;
    private $_birthday;
 
    public function __construct($id, $name, $birthday) {
        $this->setId($id);
        $this->setName($name);
        $this->setBirthday($birthday);
    }
 
    public function getName() {
        return $this->_name;
    }
 
    public function setName($name) {
        $this->_name = $name;
    }
 
    public function getId() {
        return $this->_id;
    }
 
    public function setId($id) {
        $this->_id = $id;
    }
 
    public function getBirthday() {
        return $this->_birthday;
    }
 
    public function setBirthday($birthday) {
        $this->_birthday = $birthday;
    }
 
    /**
     * 入口类自身拥有更新操作
     */
    public function update() {
        $data = array('id' => $this->_id, 'name' => $this->_name, 'birthday' => $this->_birthday);
 
        $sql = "UPDATE person SET ";
        foreach ($data as $field => $value) {
            $sql .= "`" . $field . "` = '" . $value . "',";
        }
        $sql = substr($sql, 0, -1);
 
        $sql .= " WHERE id = " . $this->_id;
 
        return DB::query($sql);
    }
 
    /**
     * 入口类自身拥有插入操作
     */
    public function insert() {
        $data = array('name' => $this->_name, 'birthday' => $this->_birthday);
 
        $sql = "INSERT INTO person ";
        $sql .= "(`" . implode("`,`", array_keys($data)) . "`)";
        $sql .= " VALUES('" . implode("','", array_values($data)) . "')";
 
        return DB::query($sql);
    }
 
    public static function load($rs) {
        /* 此处可加上缓存 */
        return new PersonGateway($rs['id'] ? $rs['id'] : NULL, $rs['name'], $rs['birthday']);
    }
 
}
 
/**
 * 人员查找类
 */
class PersonFinder {
 
    public function find($id) {
        $sql = "SELECT * FROM person WHERE id = " . $id;
        $rs = DB::query($sql);
 
        return PersonGateway::load($rs);
    }
 
    public function findAll() {
        $sql = "SELECT * FROM person";
        $rs = DB::query($sql);
 
        $result = array();
        if (is_array($rs)) {
            foreach ($rs as $row) {
                $result[] = PersonGateway::load($row);
            }
        }
 
        return $result;
    }
 
}
 
class DB {
 
    /**
     * 这只是一个执行SQL的演示方法
     * @param string $sql   需要执行的SQL
     */
    public static function query($sql) {
        echo "执行SQL: ", $sql, " <br />";
 
        if (strpos($sql, 'SELECT') !== FALSE) { //  示例,对于select查询返回查询结果
            return array('id' => 1, 'name' => 'Martin', 'birthday' => '2010-09-15');
        }
    }
 
}
 
/**
 * 客户端调用
 */
class Client {
 
    /**
     * Main program.
     */
    public static function main() {
 
 
        header("Content-type:text/html; charset=utf-8");
 
        /* 写入示例 */
        $data = array('name' => 'Martin', 'birthday' => '2010-09-15');
        $person = PersonGateway::load($data);
        $person->insert();
 
        /* 更新示例 */
        $data = array('id' => 1, 'name' => 'Martin', 'birthday' => '2010-09-15');
        $person = PersonGateway::load($data);
        $person->setName('Phppan');
        $person->update();
 
        /* 查询示例 */
        $finder = new PersonFinder();
        $person = $finder->find(1);
        echo $person->getName();
 
    }
 
}
 
Client::main();
?>


三、运行机制

●行数据入口是单条记录极其相似的对象,在该对象中数据库中的每一列为一个域。

●行数据入口一般能实现从数据源类型到内存中类型的任意转换。

●行数据入口不存在任何领域逻辑,如果存在,则是活动记录。

●在实例可看到,为了从数据库中读取信息,设置独立的OrderFinder类。当然这里也可以选择不新建类,采用静态查找方法,但是它不支持需要为不同数据源提供不同查找方法的多态。因此这里最好单独设置查找方法的对象。

●行数据入口除了可以用于表外还可以用于视图。需要注意的是视图的更新操作。

●在代码中可见“定义元数据映射”,这是一种很好的作法,这样一来,所有的数据库访问代码都可以在自动建立过程中自动生成。

四、使用场景

4.1 事务脚本

可以很好地分离数据库访问代码,并且也很容易被不同的事务脚本重用。不过可能会发现业务逻辑在多处脚本中重复出现,这些逻辑可能在行数据入口中有用。不断移动这些逻辑会使行数据入口演变为活动记录,这样减少了业务逻辑的重复。

4.2 领域模型

如果要改变数据库的结构但不想改变领域逻辑,采用行数据入口是不错的选择。大多数情况,数据映射器更加适合领域模型。

行数据入口能和数据映射器一起配合使用,尽管这样看起来有点多此一举,不过,当行数据入口从元数据自动生成,而数据映射器由手动实现时,这种方法会很有效。

数据源架构模式 - 活动记录

  【活动记录的意图】

  一个对象,它包装数据表或视图中某一行,封装数据库访问,并在这些数据上增加了领域逻辑。

  【活动记录的适用场景】

  适用于不太复杂的领域逻辑,如CRUD操作等。

  【活动记录的运行机制】

  对象既有数据又有行为。其使用最直接的方法,将数据访问逻辑置于领域对象中。

  活动记录的本质是一个领域模型,这个领域模型中的类和基数据库中的记录结构应该完全匹配,类的每个域对应表的每一列。

  一般来说,活动记录包括如下一些方法:

  1、由数据行构造一个活动记录实例;

  2、为将来对表的插入构造一个新的实例;

  3、用静态查找方法来包装常用的SQL查询和返回活动记录;

  4、更新数据库并将活动记录中的数据插入数据库;

  5、获取或设置域;

  6、实现部分业务逻辑。

  【活动记录的优点和缺点】

  优点:

  1、简单,容易创建并且容易理解。

  2、在使用事务脚本时,减少代码复制。

  3、可以在改变数据库结构时不改变领域逻辑。

  4、基于单个活动记录的派生和测试验证会很有效。

  缺点:

  1、没有隐藏关系数据库的存在。

  2、仅当活动记录对象和数据库中表直接对应时,活动记录才会有效。

  3、要求对象的设计和数据库的设计紧耦合,这使得项目中的进一步重构很困难

  【活动记录与其它模式】

  数据源架构模式之行数据入口:活动记录与行数据入口十分类似。二者的主要差别是行数据入口 仅有数据库访问而活动记录既有数据源逻辑又有领域逻辑。

  【活动记录的PHP示例】

<?php  
/**  
* 企业应用架构 数据源架构模式之活动记录 2010-10-17 sz  
* @author phppan.p#gmail.com  http://www.phppan.com  
* 哥学社成员(http://www.blog-brother.com/)  
* @package architecture  
*/ 
/**  
* 定单类  
*/ 
class Order {  
/**  
*  定单ID  
* @var <type>  
*/ 
private $_order_id;  
/**  
* 客户ID  
* @var <type>  
*/ 
private $_customer_id;  
/**  
* 定单金额  
* @var <type>  
*/ 
private $_amount;  
public function __construct($order_id, $customer_id, $amount) {  
$this->_order_id = $order_id;  
$this->_customer_id = $customer_id;  
$this->_amount = $amount;  
}  
/**  
* 实例的删除操作  
*/ 
public function delete() {  
$sql = "DELETE FROM Order SET WHERE order_id = " . $this->_order_id . " AND customer_id = "  . $this->_customer_id;  
return DB::query($sql);  
}  
/**  
* 实例的更新操作  
*/ 
public function update() {  
}  
/**  
* 插入操作  
*/ 
public function insert() {  
}  
public static function load($rs) {  
return new Order($rs['order_id'] ? $rs['order_id'] : NULL, $rs['customer_id'], $rs['amount'] ? $rs['amount'] : 0);  
}  
}  
class Customer {  
private $_name;  
private $_customer_id;  
public function __construct($customer_id, $name) {  
$this->_customer_id = $customer_id;  
$this->_name = $name;  
}  
/**  
* 用户删除定单操作 此实例方法包含了业务逻辑  
* 通过调用定单实例实现  
* 假设此处是对应的删除操作(实际中可能是一种以某字段来标记的假删除操作)  
*/ 
public function deleteOrder($order_id) {  
$order = Order::load(array('order_id' => $order_id, 'customer_id' => $this->_customer_id));  
return $order->delete();  
}  
/**  
* 实例的更新操作  
*/ 
public function update() {  
}  
/**  
* 入口类自身拥有插入操作  
*/ 
public function insert() {  
}  
public static function load($rs) {  
/* 此处可加上缓存 */ 
return new Customer($rs['customer_id'] ? $rs['customer_id'] : NULL, $rs['name']);  
}  
/**  
* 根据客户ID 查找  
* @param integer $id   客户ID  
* @return  Customer 客户对象  
*/ 
public static function find($id) {  
return CustomerFinder::find($id);  
}  
}  
/**  
* 人员查找类  
*/ 
class CustomerFinder {  
public static function find($id) {  
$sql = "SELECT * FROM person WHERE customer_id = " . $id;  
$rs = DB::query($sql);  
return Customer::load($rs);  
}  
}  
class DB {  
/**  
* 这只是一个执行SQL的演示方法  
* @param string $sql   需要执行的SQL  
*/ 
public static function query($sql) {  
echo "执行SQL: ", $sql, " <br />";  
if (strpos($sql, 'SELECT') !== FALSE) { //  示例,对于select查询返回查询结果  
return array('customer_id' => 1, 'name' => 'Martin');  
}  
}  
}  
/**  
* 客户端调用  
*/ 
class Client {  
/**  
* Main program.  
*/ 
public static function main() {  
header("Content-type:text/html; charset=utf-8");  
/* 加载客户ID为1的客户信息 */ 
$customer = Customer::find(1);  
/* 假设用户拥有的定单id为 9527*/ 
$customer->deleteOrder(9527);  
}  
}  
Client::main();  
?>

同前面的文章一样,这仅仅是一个活动记录的示例,关于活动记录模式的应用,可以查看Yii框架中的DB类,在其源码中有一个CActiveRecord抽象类,从这里可以看到活动记录模式的应用

另外,如果从事务脚本中创建活动记录,一般是首先将表包装为入口,接着开始行为迁移,使表深化成为活动记录。

对于活动记录中的域的访问和设置可以如yii框架一样,使用魔术方法__set方法和__get方法。

数据源架构模式 - 数据映射器

一:数据映射器

关系型数据库用来存储数据和关系,对象则可以处理业务逻辑,所以,要把数据本身和业务逻辑糅杂到一个对象中,我们要么使用 活动记录,要么把两者分开,通过数据映射器把两者关联起来。

数据映射器是分离内存对象和数据库的中间软件层,下面这个时序图描述了这个中间软件层的概念:

在这个时序图中,我们还看到一个概念,映射器需能够获取领域对象(在这个例子中,a Person 就是一个领域对象)。而对于数据的变化(或者说领域对象的变化),映射器还必须要知道这些变化,在这个时候,我们就需要 工作单元 模式(后议)。

从上图中,我们仿佛看到 数据映射器 还蛮简单的,复杂的部分是:我们需要处理联表查询,领域对象的继承等。领域对象的字段则可能来自于数据库中的多个表,这种时候,我们就必须要让数据映射器做更多的事情。是的,以上我们说到了,数据映射器要能做到两个复杂的部分:

1:感知变化;

2:通过联表查询的结果,为领域对象赋值;

为了感知变化以及与数据库对象保持一致,则需要 标识映射(架构模式对象与关系结构模式之:标识域(Identity Field)),这通常需要有 标识映射的注册表,或者为每个查找方法持有一个 标识映射,下面的代码是后者:

void Main()
{
    SqlHelper.ConnectionString = "Data Source=xxx;Initial Catalog=xxx;Integrated Security=False;User ID=sa;Password=xxx;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False";
    var user1 = User.FindUser("6f7ff44435f3412cada61898bcf0df6c");
    var user2 = User.FindUser("6f7ff44435f3412cada61898bcf0df6c");
    (user1 == user2).Dump();
    "END".Dump();
}

    public abstract class BaseMode
    {
        public string Id {get; set;}

        public string Name {get; set;}
    }

    public class User : BaseMode
    {
        static UserMap map = new UserMap();
        public static User FindUser(string id)
        {
            var user = map.Find(id);
            return user;
        }
    }

    public class UserMap : AbstractMapper<User>
    {
        public User Find(string id)
        {
            return (User)AbstractFind(id);
        }
       
        protected override User AbstractFind(string id)
        {
            var user = base.AbstractFind(id);
            if( user == null )
            {
                "is Null".Dump();
                string sql = "SELECT * FROM [EL_Organization].[User] WHERE ID=@Id";
                var pms = new SqlParameter[]
                {
                    new SqlParameter("@Id", id)
                };
               
                var ds = SqlHelper.ExecuteDataset(CommandType.Text, sql, pms);
                user = DataTableHelper.ToList<User>(ds.Tables[0]).FirstOrDefault();
                if(user == null)
                {
                    return null;
                }
               
                user = Load(user);
                return user;
            }
           
            return user;
        }
       
        public List<User> FindList(string name)
        {
            // SELECT * FROM USER WHERE NAME LIKE NAME
            List<User> users = null;
            return LoadAll(users);
        }
       
        public void Update(User user)
        {
            // UPDATE USER SET ....
        }
    }
   
    public abstract class AbstractMapper<T> where T : BaseMode
    {
        // 这里的问题是,随着对象消失,loadedMap就被回收
        protected Dictionary<string, T> loadedMap = new Dictionary<string, T>();
       
        protected T Load(T t)
        {
            if(loadedMap.ContainsKey(t.Id) )
            {
                return loadedMap[t.Id];
            }
            else
            {
                loadedMap.Add(t.Id, t);
                return t;
            }
        }
       
        protected List<T> LoadAll(List<T> ts)
        {
            for(int i=0; i < ts.Count; i++)
            {
                ts[i] = Load(ts[i]);
            }
           
            return ts;
        }
       
        protected virtual T AbstractFind(string id)
        {
            if(loadedMap.ContainsKey(id))
            {
                return loadedMap[id];
            }
            else
            {
                return null;
            }
        }
    }
       

上面是一个简单的映射器,它具备了 标识映射 功能。由于有标识映射,所以我们运行这段代码得到的结果是:

回归本问实质,问题:什么叫 “数据映射”

其实,这个问题很关键,

UserMap 通过 Find 方法,将数据库记录变成了一个 User 对象,这就叫 “数据映射”,但是,真正起到核心作用的是 user = DataTableHelper.ToList<User>(ds.Tables[0]).FirstOrDefault();  这行代码。更进一步的,DataTableHelper.ToList<T> 这个方法完成了 数据映射 功能。

那么,DataTableHelper.ToList<T> 方法具体干了什么事情,实际上,无非就是根据属性名去获取 DataTable 的字段值。这是一种简便的方法,或者说,在很多业务不复杂的场景下,这也许是个好办法,但是,因为业务往往是复杂的,所以实际情况下,我们使用这个方法的情况并不是很多,大多数情况下,我们需要像这样编码来完成映射:

someone.Name = Convert.ToString(row["Name"])

不要怀疑,上面这行代码,就叫数据映射,任何高大上的概念,实际上就是那条你写了很多遍的代码。

1.1 EntityFramework 中的数据映射

这是一个典型的 EF 的数据映射类,

public class CourseMap : EntityTypeConfiguration<Course>
{
    public CourseMap()
    {
        // Primary Key
        this.HasKey(t => t.CourseID);

        // Properties
        this.Property(t => t.CourseID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        this.Property(t => t.Title)
            .IsRequired()
            .HasMaxLength(100);
        // Table & Column Mappings
        this.ToTable("Course");
        this.Property(t => t.CourseID).HasColumnName("CourseID");
        this.Property(t => t.Title).HasColumnName("Title");
        this.Property(t => t.Credits).HasColumnName("Credits");
        this.Property(t => t.DepartmentID).HasColumnName("DepartmentID");

        // Relationships
        this.HasMany(t => t.People)
            .WithMany(t => t.Courses)
            .Map(m =>
                {
                    m.ToTable("CourseInstructor");
                    m.MapLeftKey("CourseID");
                    m.MapRightKey("PersonID");
                });
        this.HasRequired(t => t.Department)
            .WithMany(t => t.Courses)
            .HasForeignKey(d => d.DepartmentID);
    }
}

我们可以看到,EF 的数据映射,那算是真正的数据映射。最基本的,其在内部无非是干了一件这样的事情:

数据库是哪个字段,对应的内存对象的属性是哪个属性。

最终,它都是通过一个对象工厂把领域模型生成出来,其原理大致如下:

internal static Course BuildCourse(IDataReader reader)
{
    Course course = new Course(reader[FieldNames.CourseId]);
    contract.Title = reader[FieldNames.Title].ToString();
    …
    return contract;
}

二:仓储库

UserMap 关于 数据映射器 的概念是不是觉得太重了?因为它干了 映射 和 持久化 的事情,它甚至还得持有 工作单元。那么,如果我们能不能像 EF 一样,映射器 只干映射的事情,而把其余事情分出去呢?可以,分离出去的这部分就叫做 仓储库。

三:再多说一点 DataTableHelper.ToList<T>,简化的数据映射器

其实就是 DataTable To List 了。如果你在用 EF 或者 NHibernate 这样的框架,那么,就用它们提供的映射器好了(严格来说,你不是在使用它们的映射器。因为这些框架本身才是在使用自己的映射器,我们只是在配置映射器所要的数据和关系而已,有时候,这些配置是在配置文件中,有时候是在字段或属性上加 Attribute,有时候则是简单但庞大的单行代码)。我们当然也可以创建自己的 标准的 映射器,Tim McCarthy 在 《领域驱动设计 C# 2008 实现》 中就实现了这样的映射器。但是,EF 和 NHibernate  固然很好,但是很多时候我们还是不得不使用 手写SQL,因为:

1:EF 和 NHibernate 是需要学习成本的,这代表者团队培训成本高,且易出错的;

2:不应放弃 手写SQL 的高效性。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索string
, 数据
, 对象
, 代码
, this
模式
excel xml映射数据源、软件架构师报考入口、数据源、odbc数据源配置、jndi数据源配置,以便于您获取更多的相关知识。

时间: 2024-09-23 13:20:01

数据源架构模式 表入口 行入口 活动记录 数据映射器的相关文章

vc++-VC下SQL语句读取数据表中第n个记录数据

问题描述 VC下SQL语句读取数据表中第n个记录数据 select 列名 from 表单 语句取出的是一整列,现在想取出这一例的第n个数据,不知道如何读出 不使用 select 列名 from 表单 where 列名 = 对应值 解决方案 举个例子: select * from(select row_number() over(order by id desc) rowid,name from test) t where t.rowid = 10 --取第10条记录 解决方案二: select

.NET应用架构设计—适当使用活动记录模式代替领域模型模式

阅读目录: 1.背景介绍 2.简单介绍领域模型模式.活动记录模式 3.活动记录模式的简单示例及要点 4.总结 1.背景介绍 对软件开发方法论有兴趣的博友应该发现最近"领域驱动设计"慢慢的被人发现被人实践起来,园子里也慢慢有了DDD的学习气氛和宝贵实战经验的分享.其实之前我也痴迷于DDD,为什么会痴迷于它并不是因为它是所谓的新技术,也不是因为各种对它的炒作,而是我觉得我找到了能解放我们进行企业业务系统开发的方法论. DDD可以很好的指导我们开发可靠的软件系统,尤其是现在的企业业务复杂多变

.NET应用架构设计—表模块模式与事务脚本模式的代码编写

阅读目录: 1.背景介绍 2.简单介绍表模块模式.事务脚本模式 3.正确的编写表模块模式.事务脚本模式的代码 4.总结 1.背景介绍 要想正确的设计系统架构就必须能正确的搞懂每个架构模式的用意,而不是胡子眉毛一把抓.现在有一个现象是什么呢,项目的结构从表面上看是很不错,层分的很合理,其实对业务系统来说也就那么几种层设计方法,但是现在很多项目的逻辑架构的设计不是理想,有很多概念大家并不是很了解,当然也许每个人对技术的追求不同罢了.不管你追求不追求,事实我们还是要去往正确的方向努力才对的. 很多人包

.NET面向上下文、AOP架构模式(实现)

1.上下文Context.面向切面编程AOP模型分析 在本人的.NET面向上下文.AOP架构模式(概述)一文中,我们大概了解了上下文如何辅助对象在运行时的管理.在很多时候我们急需在运行时能把对象控制在一定的逻辑范围内,在必要的时候能让他们体现出集中化的概念,如人群.车辆.动物等等.而Context与AOP有着密切的联系,Context表示逻辑抽象的范围而AOP描述了在这个逻辑范围内如何进行控制.其实这两者都是设计模式外的设计模式,与具体的技术实现无关.[王清培版权所有,转载请给出署名] 那么Co

iOS 开发中的 Flux 架构模式

本文讲的是iOS 开发中的 Flux 架构模式, 在半年前,我开始在 PlanGrid iOS 应用程序中采用 Flux 架构(开发).这篇文章将会讨论我们从传统的 MVC 转换到Flux的动机,同时分享我们目前积累到的经验. 我尝试通过讨论代码来描述我们大部分的 Flux 实现, 它用于我们今天的产品中. 如果你只对综合结果感兴趣, 请跳过这篇文章的中间部分. 为什么从 MVC 转移 为了引入我们的决定, 我想要先谈一谈 PlanGrid 这个应用遇到的一些挑战.一些问题仅针对企业级应用程序,

.NET面向上下文、AOP架构模式(概述)

1. 上下文概述 上下文:其实就是一个逻辑上的业务.功能区域.在这个逻辑区域里可以有效的进行管理,算是一种制度的约束,也可以理解为某种范围类的数据共享. 其实在很多应用框架中到处可以看见上下文的概念,包括.NET本身的设计就建立在这种思想上的.实例化的对象默认存在于系统中的默认上下文中,我们可以构建自己的上下文将对象在运行时进行合理的管理. 在ASP.NET框架中比较经典的就是HttpContext上下文对象.所有的运行时对象都会逻辑归属到HttpContext上下文中来,如:我们可以使用Req

网站架构模式

模式描述对重复发生时间的通用解决方案的核心. 模式的价值在于可重复性. 网站架构模式 为了解决高并发访问,海量数据,高可靠运行,提出了很多解决方案实现高性能,高可用,易伸缩,可扩展,安全等技术架构. 分层 横向分成, mvc, 视图,业务,数据库层 进制跨层调用 会给以后的优化带来很多的方便 可以每层部署到不同的物理设备 分割 纵向切割, 按功能和服务包装成高内聚低耦合的模块单元. 一方面有利于开发和维护,一方面利于分布式部署,提高并发处理能力和功能扩展能力 例如将网站分为:购物,论坛,搜索,广

《流程的永恒之道》(一)控制模式之串行、并发分裂及并发汇聚模式

控制模式是流程的中枢神经,它在作战小分队中负责将多个单独的作战活动组合在一起,并推动活动的自动化流转,形成作战流程.其重要性不言而喻,因此要设计一个好的流程,就必须学会应用各种各样的控制模式. 在探寻每个模式的究竟之前,我们首先定义一个统一的格式,对于控制模式,将按照如下统一的格式进行描述: 模式描述 我们在探寻每个控制模式时,将按照如下统一的格式进行描述. 原型实例(故事片段) 给出此模式的故事片段,通过鲜活的工作流故事展现此模式的应用场景. 上下文(描述.动机) 给出此模式的具体描述和动机:

软件体系架构模式在J2EE中的应用

本文介绍了软件体系架构产生的背景和架构模式的基本理论.重点介绍管道与过滤器体系架构模式的结构,实现,优缺点等,然后以J2EE的Servlet Filter为例进行剖析它是怎样应用该架构模式的,最后简单阐述了在其它J2ee应用中(Jboss和Axis)的实践. 软件体系架构 1.软件体系架构产生背景 在经历60年代的软件危机之后,使人们开始重视软件工程的研究.来自不同应用领域的软件专家总结了大量的有价值的知识. 当初,人们把软件设计的重点放在数据结构和算法的选择上,如Knuth提出了数据结构+算法