2010/07 6
隐藏实现

代理模式(Proxy)和状态模式(State)都提供一个代理类,用来隐藏真正的实现过程。在调用代理类时,他简单的将请求转发给实际类去处理,并返回其结果。这两种设计模式比较相似,代理模式可以看做是一种特殊的状态模式,他只有一个状态。一个观点是将这两者合并,称之为代理模式(Surrogate)。但Proxy这个词汇使用的太久了,概念被固化了。因此,这两个模式并没有被合并。

最开始的想法很简单,通过代理类,以实际类做支持,来完成实际的实现功能。



代理对象被建立后,他可以提供一个应用接口,将所有的调用转发给实际类。

在结构上,代理模式和状态模式很容易区分:代理模式只有一个应用,状态模式则有多个。《设计模式》一书的看法不同:代理模式用来控制对类的访问权限,状态模式这用来在运行过程中动态的改变类。

代理

我们来为上图的代理模式写些代码:

 
#: c04:ProxyDemo.py 
# Simple demonstration of the Proxy pattern. 
 
class Implementation: 
  def f(self):  
    print "Implementation.f()" 
  def g(self):  
    print "Implementation.g()"  
  def h(self):  
    print "Implementation.h()"  
 
class Proxy: 
  def __init__(self):  
    self.__implementation = Implementation()  
  # Pass method calls to the implementation:
  def f(self): self.__implementation.f()  
  def g(self): self.__implementation.g()  
  def h(self): self.__implementation.h()  
 
p = Proxy() 
p.f(); p.g(); p.h() 
#:~ 

Proxy类的接口并不需要和Implementation类的接口保持完全一致,代理可以以任何方式来“代言”实际类。一般来讲,将代理类和实际类保持一致的接口会更为通用和方便,也能够保证实际类完全支持代理类的所有调用。

当然,在python中,我们可以使用内置的代理机制。简化后的代码像这样:

 
#: c04:ProxyDemo2.py 
# Simple demonstration of the Proxy pattern. 
 
class Implementation2: 
  def f(self):  
    print "Implementation.f()" 
  def g(self):  
    print "Implementation.g()"  
  def h(self):  
    print "Implementation.h()"  
 
class Proxy2: 
  def __init__(self):  
    self.__implementation = Implementation2()  
  def __getattr__(self, name): 
    return getattr(self.__implementation, name) 
 
p = Proxy2() 
p.f(); p.g(); p.h(); 
#:~ 

Proxy2使用__getattr__( )方法,这看起来更为优雅,他不依赖于任何的实施细节。


状态模式

和代理模式相比,状态模式中存在多个实现类,并提供了在实现类中动态切换的接口。

 
#: c04:StateDemo.py 
# Simple demonstration of the State pattern. 
 
class State_d: 
  def __init__(self, imp):  
    self.__implementation = imp  
  def changeImp(self, newImp): 
    self.__implementation = newImp 
  # Delegate calls to the implementation: 
  def __getattr__(self, name): 
    return getattr(self.__implementation, name) 
 
class Implementation1: 
  def f(self):  
    print "Fiddle de dum, Fiddle de dee,"  
  def g(self):  
    print "Eric the half a bee."  
  def h(self):  
    print "Ho ho ho, tee hee hee,"  
 
class Implementation2: 
  def f(self):  
    print "We're Knights of the Round Table."  
  def g(self):  
    print "We dance whene'er we're able."  
  def h(self):  
    print "We do routines and chorus scenes"  
 
def run(b): 
  b.f() 
  b.g() 
  b.h() 
  b.g() 
 
b = State_d(Implementation1()) 
run(b) 
b.changeImp(Implementation2()) 
run(b) 
#:~


在程序中,我们先构造了一个实现类,并将其封装到State_d。运行一段时间后,程序又被切换给另一个实现类。


代理模式和状态模式有不同的使用场景。《设计模式》描述了代理模式的主要场景:

1. 远程代理
2. 虚拟代理,提供“惰性类”
3. 保护代理 用于限制客户端对被代理对象的完全访问。
4. 转发 建立代理时,增加一些额外的操作,用来对调用进行跟踪。

在pyhton引用中,使用了不少的保护代理,用来阻止对真实对象的访问。比如,你无法建立使用一个对NULL的引用。


状态机模式

状态模式允许客户端程序在运行过程中修改其实现过程,我们可以在实现过程中,将一个实施自动的转变为另一个实施,这样的实现,我们称之为状态机模式。当前的运行状态代表系统当前的状态,而状态可以由系统自动的切换。最基本的状态机模式是对象状态。

切换系统状态一般可以使用上述模板方法中所介绍的代码。

每一个状态都使用run()接口实现其具体行为,或者你也可以传入一个input参数,以便告诉系统,你应该切换的下一个状态是什么。这两种设计的主要不同点是由谁来决定下一个状态是什么。我们可以传入一个input参数,标示下一个状态,或者,在状态类中定义一个表(或者定一个全局表),定义当前状态的下一个状态是什么。
 
#: c04:statemachine:State.py
# A State has an operation, and can be moved
# into the next State given an Input:
class State:
	def run(self):
		assert 1, "run not implemented"
	def next(self, input):
		assert 1, "next not implemented"
#:~

这个类并不是很完整,但他足以说明状态类的代码结构,如果其子类没有重构其所有方法时,他也可以给出一个简短的错误提示。更简单,我们可以直接定义为:
 
class State: pass

因为如果run或next没有被实现,系统同样也会抛出异常。


状态机保存了状态的轨迹,这些轨迹一般定义在状态机的构造函数中。runAll方法将对所有的input对象实施状态操作及变更。run方法则只执行其特定的对象的状态操作及变更。
 
#: c04:statemachine:StateMachine.py
# Takes a list of Inputs to move from State to
# State using a template method.
class StateMachine:
	def __init__(self, initialState):
		self.currentState = initialState
		self.currentState.run()
	# Template method:
	def runAll(self, inputs):
		for i in inputs:
			print i
			self.currentState = self.currentState.next(i)
			self.currentState.run()
#:~

我将runAll方法也写作成了模板方法同样的形式,尽管这并不是必须的。

目前,状态机模式的基本框架已经完成了。下面我们将使用捕鼠器做为示例来惊醒一个演示(放心,没有哪只老鼠会收到伤害)。我们可以操作捕鼠器的各个状态,老鼠类及其星系将放到mouse这个包中,主要包括老鼠的移动行为,他将作为状态机的输入参数。
 
#: c04:mouse:MouseAction.py
class MouseAction:
	def __init__(self, action):
		self.action = action
	def __str__(self): return self.action

	def __cmp__(self, other):
		return cmp(self.action, other.action)
	# Necessary when __cmp__ or __eq__ is defined
	# in order to make this class usable as a
	# dictionary key:
	def __hash__(self):
		return hash(self.action)

# Static fields; an enumeration of instances:
MouseAction.appears = MouseAction("mouse appears")
MouseAction.runsAway = MouseAction("mouse runs away")
MouseAction.enters = MouseAction("mouse enters trap")
MouseAction.escapes = MouseAction("mouse escapes")
MouseAction.trapped = MouseAction("mouse trapped")
MouseAction.removed = MouseAction("mouse removed")
#:~

我们注意到__cmp__( )被重构了,用来比较两个action对象的值。每一种移动行为都被定义在MouseAction对象中,成为该对象的一个属性。

为此,我们再建立一个测试用例,创建一个老鼠的行为队列:
 
#:! c04:mouse:MouseMoves.txt
mouse appears
mouse runs away
mouse appears
mouse enters trap
mouse escapes
mouse appears
mouse enters trap
mouse trapped
mouse removed
mouse appears
mouse runs away
mouse appears
mouse enters trap
mouse trapped
mouse removed
#:~


有了以上的这些基础,我们现在可以开始编写老鼠夹的代码了。每一个状态子类都定义了run的方法。也有if语句用来选择下一个状态是什么。

 
#: c04:mousetrap1:MouseTrapTest.py 
# State Machine pattern using 'if' statements 
# to determine the next state. 
import string, sys 
sys.path += ['../statemachine', '../mouse'] 
from State import State 
from StateMachine import StateMachine 
from MouseAction import MouseAction 
# A different subclass for each state: 
 
class Waiting(State): 
  def run(self):  
    print "Waiting: Broadcasting cheese smell" 
 
  def next(self, input): 
    if input == MouseAction.appears: 
      return MouseTrap.luring 
    return MouseTrap.waiting 
 
class Luring(State): 
  def run(self): 
    print "Luring: Presenting Cheese, door open" 
 
  def next(self, input): 
    if input == MouseAction.runsAway: 
      return MouseTrap.waiting 
    if input == MouseAction.enters: 
      return MouseTrap.trapping 
    return MouseTrap.luring 
 
class Trapping(State): 
  def run(self): 
    print "Trapping: Closing door" 
 
  def next(self, input): 
    if input == MouseAction.escapes: 
      return MouseTrap.waiting 
    if input == MouseAction.trapped: 
      return MouseTrap.holding 
    return MouseTrap.trapping 
 
class Holding(State): 
  def run(self): 
    print "Holding: Mouse caught"  
  def next(self, input): 
    if input == MouseAction.removed: 
      return MouseTrap.waiting 
    return MouseTrap.holding 
 
class MouseTrap(StateMachine): 
  def __init__(self):  
    # Initial state 
    StateMachine.__init__(self, MouseTrap.waiting) 
 
# Static variable initialization: 
MouseTrap.waiting = Waiting() 
MouseTrap.luring = Luring() 
MouseTrap.trapping = Trapping() 
MouseTrap.holding = Holding() 
 
moves = map(string.strip,  
  open("../mouse/MouseMoves.txt").readlines()) 
MouseTrap().runAll(map(MouseAction, moves)) 
#:~


状态机类的定义了所有可能的状态类型,并建立了初始状态。单元测试程序建立了一个老鼠夹,并运行了我们刚刚建立的老鼠行为队列。

在next()方法中使用if方法是可行的,但是在状态比较多的时候,使用if则会变得很难维护。一个更好的办法是在每个状态内部建立一个表,并基于传入参数进行自动判断。

这乍看起来很容易,我们可以在每一个子状态中建立一个静态表,定义其下一个状态元素。但是,这将造成各个状态类之间的循环依赖关系。为了解决这个问题,我们只能在调用next方法时,才惰性得再加载这个状态表。因为这个原因,next的写法看起来会有些怪。

我们重新定义了上述的State类,并将其命名围StateT,他增加了一个Map并将其初始化为一个二位数组。next方法定义了一个基本实现逻辑,StateT子类的next也必须调用该方法。
 
#: c04:mousetrap2:MouseTrap2Test.py 
# A better mousetrap using tables 
import string, sys 
sys.path += ['../statemachine', '../mouse'] 
from State import State 
from StateMachine import StateMachine 
from MouseAction import MouseAction 
 
class StateT(State): 
  def __init__(self): 
    self.transitions = None 
  def next(self, input): 
    if self.transitions.has_key(input): 
      return self.transitions[input] 
    else: 
      raise "Input not supported for current state" 
 
class Waiting(StateT): 
  def run(self):  
    print "Waiting: Broadcasting cheese smell" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = {  
        MouseAction.appears : MouseTrap.luring  
      } 
    return StateT.next(self, input) 
 
class Luring(StateT): 
  def run(self): 
    print "Luring: Presenting Cheese, door open" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = { 
        MouseAction.enters : MouseTrap.trapping, 
        MouseAction.runsAway : MouseTrap.waiting 
      } 
    return StateT.next(self, input) 
 
class Trapping(StateT): 
  def run(self):     print "Trapping: Closing door" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = { 
        MouseAction.escapes : MouseTrap.waiting, 
        MouseAction.trapped : MouseTrap.holding 
      } 
    return StateT.next(self, input) 
 
class Holding(StateT): 
  def run(self): 
    print "Holding: Mouse caught" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = { 
        MouseAction.removed : MouseTrap.waiting 
      } 
    return StateT.next(self, input) 
 
class MouseTrap(StateMachine): 
  def __init__(self):  
    # Initial state 
    StateMachine.__init__(self, MouseTrap.waiting) 
 
# Static variable initialization: 
MouseTrap.waiting = Waiting() 
MouseTrap.luring = Luring() 
MouseTrap.trapping = Trapping() 
MouseTrap.holding = Holding() 
 
moves = map(string.strip,  
  open("../mouse/MouseMoves.txt").readlines()) 
mouseMoves = map(MouseAction, moves) 
MouseTrap().runAll(mouseMoves) 
#:~


其他的代码也是一样的,不同的只在于StateT的类名和next方法的具体实现上。

当你不得不建立或维护大量的状态时,使用这样的方式无疑是必要的。通过查看状态表,将很容易阅读并理解这些状态。

Defined tags for this entry: , , ,

Posted by rollenc

Last modified on 2010-07-21 11:00
2007/04 13
经过一周的纯正PHP5环境下的工作,我确定了自己现在的事情:
把现有的环境当成试验场。
前一阵学习了不少的重构,设计模式等只是,但是,以前的开发一直要考虑PHP4的兼容性,故而在编码上看起来不伦不类的。受到语言限制,也有诸多的模式实现起来非常困难或者诡异。现在我可以大胆的进行完整的OOP。
把所有沉睡的知识召唤醒来吧!
UML,OOP,PHP5,Design patterns,Refactoring...
Defined tags for this entry: , , ,

Posted by rollenc

Last modified on 2007-04-17 12:12
2007/01 24
本来向把这些文章翻译过来的,一直太忙,时间顾不上。简单的总结和说明一下,就像是做点笔记和说明。

The Singleton and Factory Patterns in PHP: Building object-oriented forms (建立面向对象的表单)
The Singleton and Factory Patterns in PHP: designing an object factory (实现工厂)
The Singleton and Factory Patterns in PHP: a rendering-capable factory class (认识工厂模式)
The Singleton and Factory Patterns in PHP: Working With Singletons (使用单例模式)
The Singleton and Factory Patterns in PHP: Building a Form Generator Class (建立表单生成类)

rollenc笔记:
1。单例:在系统中只需要一个实例是可以使用单例模式。你一天可能需要吃多个苹果,而你只需要一把水果刀。而且,没有水果刀就去拿一把,已经有的话就直接用,不需要忽略以前的再拿新的。那么水果刀就可以作为一个单例。
在建立数据库连接是常常需要使用单例模式。在MVC系统中,也常常使用单例来调用module。在简单的代码如下:
class Db
{
    /**
     * @access private
     */
    function Db()
    {
            $this->conn = mysql_connect(DB_HOST, DB_USER, DB_PWD);
            if(!$this->conn)
            {
                die("Connect DB error!");
            }
            mysql_select_db(DB_NAME);
    }
    /**
     * 使用 $db = & Db::getInstance() 来构建一个DB连接,而不是使用$db = new Db();
     * 如果使用php5,可以把Db的构造函数__construct声明为private,这样在程序级强行在程序只能使用getInstance来构建,
     * 但考虑兼容的代码,在php4中就只能简单的靠程序员自己来自觉遵守了。
     */
    function & getInstance()
    {
            if (!DB :: $instance)
            {
                    DB :: $instance = new Db();
            }
            return DB :: $instance;
    }
    /**
     *其他的函数等等
     */
    function query($query)
    {
       //Your code here
    }
}
?>


2。简单工厂:文中提到的工厂属于简单工厂模式的范畴。有几个类继承于同一个类或者实现了相同的接口(文中并没有接口和继承,但是可以知道几个)。而在运行前,你并不知道你需要那一个类,那么,。你可能需要一个工厂。比如:
output();
?>

在运行前,我们并不知道,我们需要建立一个什么样的Fruit对象,那么我们就把参数$_GET['name']给FruitFactory,让他来生产一个相应的Fruit对象出来。然后,我们再继续进行下面操作。我提到上面的接口的概念,也是因为后面的调用是相同的,只有具备了这些接口的对象(类)才能继续正确的运行。
Defined tags for this entry:

Posted by rollenc

Last modified on 2007-01-25 10:27
2007/01 15
一直在学习设计模式这方面的东西,以前在wiki上写了一阵,把自己的学习成果写(当然很多时候是ctrl+c & ctrl+v)下来,但渐渐发现mediawiki的语法和可扩展性是无法接受的。也就暂停了这个记录。

现在开始,真得给自己压力,在blog上写出些自己在设计模式下的学习笔记了。包括自己的实践代码和理解,疑问等。

修改:wikimepia错别字改为mediawiki
Defined tags for this entry: ,

Posted by rollenc

Last modified on 2007-07-11 14:38
2006/11 30
上一篇BLOG以及这一篇都是使用Performancing来发布的,感觉很不错。比FLOCK上的功能要强多了。wordpress上几乎所有的功能都可以使用到,比如Category选取,发布为草稿,也支持编辑以前发布的文章。
功能非常棒。赶快下载使用吧:
Firefox的Performancing插件下载地址
Defined tags for this entry: , ,

Posted by rollenc

Not modified
2006/11 30
来源:http://www.developer.com/lang/php/article.php/10941_3604111_1
Part1:
PHP 5 made significant improvements on the Object Orientated programming model of PHP 4 bringing it more in line with languages such as Visual Basic .NET and Java. The improved object model in PHP 5 makes developing applications using OOP much easier and gives you the programmer, greater flexibility.

In this series of articles I will demonstrate the new features of the PHP 5 object and show you how to create a database abstraction layer similar to PEAR DB. I will also introduce you to a few design patterns that can be applied to common OOP related problems.

In this article, I introduce you to some of the features of the PHP 5 object model. You will see how to create a database abstraction layer similar to the Pear DB abstraction layer. You'll also learn how to adapt this abstraction layer for your own uses.

Introduction


One of PHP's stronger areas is its support for database connectivity. It is able to connect to and talk to just about any database server or interface you can imagine. However, with this comes a few inherent problems; each database system has its own features, functions and in most cases they have their own versions of SQL. Although the functions used to access these databases are similar they do vary subtly meaning that if you were to want to port an application written for MySql to MS SQL server, the refactoring would require manually changing all calls to mysql_query() to mssql_query().

While we are not going to go as far as developing a database independent version of SQL, the new features of PHP 5 will be us build a consistent database API with support for stored procedures (where it is not already present). This will then make switching from one database system to another as painless as changing one line of code.



Interfaces Abstract Classes and the Adapter Pattern


The first features new to PHP 5 to be covered in this article are abstract classes and interfaces. These concepts are nothing more than features added to OOP, which help the programmer follow good coding standards.



Abstract Classes


An abstract class is a class that is only partially implemented by the programmer. It may contain one or more abstract methods. An abstract method is simply a function definition that serves to tell the programmer that the method must be implemented in a child class.



To create an abstract class we use the code shown in Listing 1:


Listing 1: An Abstract PHP class


SerialNumber = $SerialNumber;  
    }
    public function getSerialNumber()  
    {  
        return $this->SerialNumber;  
    }  
}  
?>

The abstract class in Listing 1 contains some of the methods required for a weapon. The fire() method however, cannot be implemented because each different weapons use different firing different mechanisms. The method is therefore declared as abstract, meaning it will be implemented in a more specific child class.


Because the class is abstract, an instance of it can never be created (remember, it is only a partial implementation). Instead a child class must be created using inheritance and implement the fire method in itself. Failure to do so will result in a fatal error. Listing 2 shows a child class being created from the Abstract Weapon class.


Listing 2: Extending the Abstract Weapons class


SafetyOff) {  
            return $this->CurrentBullet;  
        }  
    }  
}  

class Cannon extends Weapon  
{  
    public function fire()  
    {  
        $this->NeedsLoading = true;  
        return $this->CurrentCanon;  
    }  
?>


An instance of the Cannon and Gun classes can now be created because they now fully implemented subclasses of weapon.


Interfaces


An interface is similar to an abstract class; indeed interfaces occupy the same namespace as classes and abstract classes. For that reason, you cannot define an interface with the same name as a class. An interface is a fully abstract class; none of its methods are implemented and instead of a class sub-classing from it, it is said to implement that interface.


An interface will be used in the database abstraction layer you create. This ensures that every time you create a class for a particular database, the same API is exposed. When using an interface, you can then rely on the methods defined for the interface to be part of the class because, if they are not, PHP will not parse it.


The MySql functions will be used as an example because they are the most commonly used amongst PHP programmers. The most commonly used functions are:


  • mysql_connect()
  • mysql_error()
  • mysql_errno()
  • mysql_query()
  • mysql_fetch_array()
  • mysql_fetch_row()
  • mysql_fetch_assoc()
  • mysql_fetch_object()
  • mysql_num_rows()
  • mysql_close()

If all the database class APIs you create can expose the same methods with the same return types then you can be sure that changing from one database to another, such as from MySql to Postgre SQL, will be painless. As such, the interface in listing 3 can be determined for your API.

Listing 3: An Abstracted Database Interface


interface DB 
{ 
    public function connect(); 
    public function error(); 
    public function errno(); 
    public static function escape_string($string); 
    public function query($query); 
    public function fetch_array($result); 
    public function fetch_row($result); 
    public function fetch_assoc($result); 
    public function fetch_object($result); 
    public function num_rows($result); 
    public function close(); 
} 

Any class implementing the interface must define each method that is declared in the interface, and each method must have at least the parameters identified in their interface definitions. It may have more parameters as long as they are optional, but it cannot have less.

Part2

Look at a class in Listing 4 that implements the database interface. You should recall that I mentioned the adapter pattern earlier. This is an example of the adapter pattern, which is used by programmers in order to adapt one API. The API you are adapting from could be another object-based API or as being done here, an adaptation from a modular API. If you want to read more about the adapter pattern, you can find a more detailed explanation and examples here.

Notice how the escape_string() method is included as a static method. This method does not require an active connection to a database and should not require and instance of any object which implements the DB interface. In my opinion, this is the single most important method of any database implementation; a poorly implemented escape string method could make your applications vulnerable SQL injection.


Listing 4: Implementing the database interface


class MySqlDB implements DB 
{ 
        private  $link; 
         
        public function connect($server='', $username='', $password='', $new_link=true, $client_flags=0) 
        { 
            $this->link = mysql_connect($server, $username, $password, $new_link, $client_flags); 
        } 
     
        public function errno() 
        { 
            return mysql_errno($this->link); 
        } 

        public function error() 
        { 
            return mysql_error($this->link); 
        } 

        public static function escape_string($string) 
        { 
            return mysql_real_escape_string($string); 
        } 

        public function query($query) 
        { 
            return mysql_query($query, $this->link); 
        } 
         
        public function fetch_array($result, $array_type = MYSQL_BOTH) 
        { 
            return mysql_fetch_array($result, $array_type); 
        } 

        public function fetch_row($result) 
        { 
            return mysql_fetch_row($result); 
        } 
         
        public function fetch_assoc($result) 
        { 
            return mysql_fetch_assoc($result); 
        } 
         
        public function fetch_object($result) 
        { 
            return mysql_fetch_object($result); 
        } 
         
        public function num_rows($result) 
        { 
            return mysql_num_rows($result); 
        } 
         
        public function close() 
        { 
            return mysql_close($this->link); 
        } 
}
?>


You'll notice that there are many more mysql functions than methods that are adapted in the interface in listing 3. However, this small subset of functions is sufficient to meet the needs of most applications requiring trivial data storage and retrieval. The additional functions can be implemented and I have done this in the attached example file, you may also choose to add additional functionality to the class and the interface.


Listing 5: Creating a database class


    $db = new MySqlDb; 
    $db->connect('host', 'username', 'password'); 
    $db->query('use users'); // we could also use $db->select_db here but it is not consistent with the interface 

    $result = $db->query("SELECT username FROM users"); 
         
    while($row = $db->fetch_assoc($reuslt)) 
    { 
        echo($row['username']); 
    } 

As shown in listing 5, you can now create a class for each database you want and as long as it implements the DB interface, switching from one to another is as easy as changing one line of code:


$db = new MsSqlDb; 

Conclusion


In this first article, you've seen how to create an abstraction layer to access a database. Using this, you saw how creating an interface helps you to isolate your application so that you can easily switch from one database to anther without rewriting your own applications.


Downloads


About the Author


Adam Delves is a university student and web programmer from the UK who is studying computing. He has been a PHP programmer for over 3 years and now runs two small websites and writes articles for PHP builder.com.

rollenc总结


将本文标题相对应,MySqlDb实现了DB接口(interface),也对mysql_*函数进行了适配(Adapter)(我就很喜欢进行这种适配,php中有很多带‘_’字符的函数(这也被PHP反对者们发现,并抨击PHP的一大有力证据),与我喜欢的骆驼编程风格很不协调,所以,为了隐藏它们,我常常进行适配)。
抽象类只在weapon上出现到了,为了增加代码的灵活性,建议使用接口,而不是继承。(完)
Defined tags for this entry: , ,

Posted by rollenc

Last modified on 2007-01-12 18:56
2006/11 28
终于把DB这一个模块整理出来了,简单的分析一下几个类之间的关系以及其中的设计模式:
类图如下:

sugar DB类图


顺序图如下:
DB 顺序图

从类的模式及其构建一个DBManager的流程来看,这使用了单例模式,而其中是创建哪一个类,则使用桥梁模式来封装。但是在代码中我还看到了一些地方直接使用了DBManager::getInstance()方法来建造(获取)数据库实例,虽然使用上调用DBManagerFactory::getInstance()和DBManager::getInstance()这两个静态函数并无差别,DBManagerFactory::getInstance只是简单的委托给DBManager::getInstance,但是在顺序图流程上就不好解释了。这打乱了整个设计模式的结构。
当然,如果单单说是从速度上解释的话可以理解,使用DBManager::getInstantce可以减少一次函数调用。但这样混乱了整个设计模式,我觉得这代价是不是大了。
希望有高人指点一二,说说其中我忽略和分析错误了的道理。
Defined tags for this entry: , ,

Posted by rollenc

Not modified
2006/11 27
由于sugarOS考虑了PHP4的兼容性,虽然代码架构中在设计模式上表现不错,但由于缺少很多的面向对象关键字,比如(public,private abstract)等,也缺少一些面向对象的功能,如(interface)等。这在很大程度上影响了代码的可阅读性以及限制了一些设计模式的使用。
比如如下代码段:
[PHP]
class DBManager
{
var $helper;
var $tableName;
var $database = null;
var $dieOnError = false;
var $encode = true;
var $query_time = 0;
var $lastmysqlrow = -1;
var $last_error = '';
var $lastResult = array ();
function DBManager()
{

global $sugar_config;

$my_db_helper = 'MysqlHelper';
if ($sugar_config['dbconfig']['db_type'] == "oci8")
{

}
if ($sugar_config['dbconfig']['db_type'] == "mssql")
{
$my_db_helper = 'MssqlHelper';
}
static $helper;
if (empty ($helper))
{
$helper = new $my_db_helper ();
}
$this->helper = $helper;
}

function & getInstance($instanceName = '')
{
global $sugar_config;
static $count;
static $old_count;
global $dbinstances;

$instanceName = 'db';
$config = $sugar_config['dbconfig'];

if (!isset ($dbinstances))
{
$dbinstances = array ();
}

if (!isset ($dbinstances[$instanceName]))
{

$my_db_manager = 'MysqlManager';
if ($config['db_type'] == "oci8")
{

}
else
if ($config['db_type'] == "mssql")
{
$my_db_manager = 'MssqlManager';
}
if (!empty ($config['db_manager']))
{
$my_db_manager = $config['db_manager'];
}

DBManagerFactory :: load_db_manager_class($my_db_manager);
$dbinstances[$instanceName] = new $my_db_manager ();
$dbinstances[$instanceName]->connect($config, true);
$dbinstances[$instanceName]->count_id = $count;
$dbinstances[$instanceName]->references = 0;
$dbinstances[$instanceName]->helper->db = $dbinstances[$instanceName];

}
else
{
$old_count++;
$dbinstances[$instanceName]->references = $old_count;

}

return $dbinstances[$instanceName];
}
//MORE
}
[/PHP]
DBmanager是一个抽象类,也是一个单例类,故DBmanager类声明应该是abstract class, 构造函数好像不该出现或者是private,getInstance函数也该是static等等,这样,对于设计模式的理解更方便些。
我准备对其重构了,不是为了使用或者速度,仅仅是把代码改一改,使它更象一个面向对象的系统。
当然,一开始改,PHP4支持肯定就挂掉了。
Defined tags for this entry: , , , ,

Posted by rollenc

Not modified
2006/11 26
最近几天一直在研究SugarOS,主要在学习其中设计模式和编程风格等。
其中使用了以下的工具和组件等:
  • Eclipse & PHPEclipse。 我对比了一下DreamWeaver(DW),Zend Studio(ZS),Eclipse & PHPEclipse(E&PE)三种开发工具,厌倦DW的全站搜索功能,各个文件间的关联很松散。ZS强在逐步调试,但好像我并不需要,从大局把握整个系统才是最重要的。另外就是ZS的速度让我的256机子疯掉了。E&PE是最佳的选择,整个系统完整的融合在一起,不需要ctrl+F就可以在相关联的函数,类中跳转。
  • Simple Test 试着以测试的方式去思考。不过我更希望是测试驱动开发。这样更有趣些。唯一的遗憾是Simple Test for eclipse的插件没有安装好,各个文件间的包含关系处理不正常,看了一下readme文件,有这么一句:
    Future Features These are features that should eventually make it into this plugin * Allow different "include" file on each runner (override the "master" include) * Handle fatal errors better
    所以,只能等待下一个版本出来了。现在先在WEBPAGE里面用Simple Test吧。
  • 重构 我没有准备去重构这个系统,几天的代码阅读,也没有问到“代码臭味”,但是我会在代码中去理解,重构的目标:设计模式。
  • 设计模式 这是我一眼看中这个系统并把它作为我的学习对象的原因。先在再看DB部分,对整个的构建模式有了很大的体会。不过,完全理解这个系统的代码对现在的我来说还是有困难的,在复杂的工厂模式中还是会迷路,找不到系统运行的流向。





Defined tags for this entry: , , , ,

Posted by rollenc

Not modified
2006/11 19
很久没写过读后感了,估计上一次还是小学时代看电影时。也就因为这个,特讨厌学校放电影。
这不是读后感,因为我现在还在慢慢的读。有点惊讶,有点昏头,也有点。。。什么感觉都有,想骂人的感觉都有。
我很佩服阎宏了,再一本程序员阅读的书里面可以写这么多的哲学,古文,和一些其他的知识。第一章就看的我昏,从形而上学──我一直没弄明白第一次说这个词的人是不是中国人──开始论,涉及
1、道家观点:无名大地之始,有名万物之母──老子云
2、量子物理中波和粒子我一个理科本科差生看不懂的东西云云
3、马王堆出土道德经贴图
4、成玄英(601~690)之《庄子疏》:气聚而有其形,气散而归于无形也。
5、建筑风水学:气乘风则散,界水则止;
等等云云。。
后面不少西游记例子,唐僧和徒弟的一对多的关系,徒弟是抽象类,悟空,八戒是徒弟的继承;孙大圣的身外身法术。还有鲁智深为什么是和尚的道理。
昏昏头。我已经对阎宏佩服的五体投地了,简直想把往上留传的那段赞扬楼主发帖的回帖记下来,背给阎宏大哥听。
说回来,这本书也是我看到的最浅显易懂的涉及模式的书了。哲学古文相关的东西不解,但程序部分还是很容易理解的。
谢谢阎宏老师了,在教我程序的同时,也让我补回了一点小学初中高中大学里面一直没学习好的中国古代文化和哲学。

附记:
哲学:比这句话“你是人,会制作和使用劳动工具的人”的回答更没用的知识。 (摘自:rollenc无知词典)
Defined tags for this entry: , ,

Posted by rollenc

Not modified
2006/11 12
这一节基本学习完毕,标记一下。
详细信息请查阅本站WIKI。
抽象工厂模式
Defined tags for this entry: , ,

Posted by rollenc

Not modified