当前位置:首页 > 开发 > 编程语言 > 编程 > 正文

程序设计语言--结构化,面向对象,接下来要怎么走?

发表于: 2006-02-07   作者:歆渊   来源:转载   浏览:
摘要: 软件设计从最原始的机器指令走到今天企业级这一步,经历了无数革命性的演进和变革. 由计算机运算能力和普及程度的高速发展所推动的软件生产业的屡屡不适,正给各种新思想,新事物的诞生创造了土壤,使得这个领域的创造性活动非常活跃. 从机器语言到汇编语言,从汇编语言到类自然语言; 从头到尾的单条控制流到归纳出重用函数的结构化方法,再到进一步封装和重用的面向对象方法. 每一次进步都是激动人心的变革. 然而面向

软件设计从最原始的机器指令走到今天企业级这一步,经历了无数革命性的演进和变革. 由计算机运算能力和普及程度的高速发展所推动的软件生产业的屡屡不适,正给各种新思想,新事物的诞生创造了土壤,使得这个领域的创造性活动非常活跃.

从机器语言到汇编语言,从汇编语言到类自然语言; 从头到尾的单条控制流到归纳出重用函数的结构化方法,再到进一步封装和重用的面向对象方法. 每一次进步都是激动人心的变革.
然而面向对象方法如日中天,极尽辉煌的今天,面对新生的很多挑战和问题,也开始显得苍白无力; 睿智的架构师和程序开发者都在为这些问题的解决寻找着更先进有效的方案, 层出不穷的体系架构,开发框架,包括J2EE等很"官方"的规范, 无不是这些努力的一个个生动体现.

然而OSI的7层模型最终没有代替TCP/IP的5层模型, 虽然它更为先进和完美. 我觉得众多厂商和用户的偏向支持是一个表象的原因, 这个原因的原因, 是因为7层模型毕竟没有比5层模型有本质的优势, 商业环境一直是追求性价比的效率优先原则,我们可以说是用7层替换5层的代价太大,但也可以说是这么做的好处不够大.

那么在程序设计方法学领域,我们会不会像互联网基础设施一样,最终找不到一个本质性演进的出路呢? 我们能发明并且实现出比现有这些架构和框架有压倒性优势的编程语言级别的机制,有所突破吗?

我的答案是: 有! 但是绝非易事. 同时, 我希望这一次本质性的演进,能够由中国人来完成.

企业级软件工程的新特性,我认为核心在于规模的可伸缩性,以及人力资源角色的细分所带来的协作要求.

对于应用规模的可伸缩性,需要一系列核心技术来支持,可能通过群集,网格等等,这些技术已经足够高深到没法让一个企业要求它的大部分开发人员都熟悉和掌握相关的开发技巧和能力. 这其实可以归结为需要把掌握这些核心技术的外部专业团队作为企业本身开发队伍的一个角色来看待和协调的问题. 所以最终, 开发人力资源的多元化, 如何分配其角色,如何协调他们之间的交流和合作,成为企业级软件开发过程的主体问题.

那么现在我们就可以发现,与迎面而来的多角色化软件开发需求相比,面向对象的程序设计方法已经相形见拙,它所知道能够打交道的角色只有一个: 程序员.

逻辑注入是解决这个问题的一种方法, 也就是更聪明的程序员担当起其中一个角色, 那就是小心的在普通应用程序员不知道的情况下, 让他的代码有一些新的功能和表现. 然而这需要极大的技巧和悟性, 同时冒不小的风险. 从AOP的成功可见很多人已经选择了这种方式.
J2EE EJB实现的本质其实还是逻辑注入, 只是它通过官方的"规范", 比较好的约束了应用程序员的作风, 降低了窜改代码的风险. 但是对于实现支持的应用服务器/容器来讲, 代码生成几乎是唯一的手段.

当然,我也知道接口是个很好的东西,在很大程度上也能解决这个问题. 但是别忘了,接口中的东西必须全部是public修饰的,在java中你即使不这么写,编译器也会给你自动加上去. 这带来的是一种退化, 好像回到了C语言的时代,没有权限修饰符,有人给你一个struct,里面全是函数指针.

现在让我们来设想一下,如果下一代程序设计语言被设计为有角色概念,同时能够支持不同角色的代码之间通过一定的接口进行交互的话,程序将会怎么变化.

我们以一个餐馆,它营业过程中需要洗脏盘子的案例来模拟程序的各种写法:

1. 最初,这个餐馆很小,盘子都是由一个洗完工(DishWasher)自己来洗.

public class Dish
{
 private boolean dirty=false;
 public boolean isDirty()
 {
  return dirty;
 }
 
 public void use()
 {
  dirty = true;
 }
 
 public void wash()
 {
  dirty = false;
 }
}

public class Food
{
 private String kind;
 private double amount;
 
 Food(String kind, double amount)
 {
  this.kind = kind;
  this.amount = amount;
 }
 
 public String getKind()
 {
  return kind;
 }
 
 public double getAmount()
 {
  return amount;
 }
}

public class Restaurant
{
 public class Meal
 {
  private Dish dish;
  private Food food;
  
  Meal(Dish dish, Food food)
  {
   this.dish = dish;
   dish.use();
   this.food = food;
  }
  
  public void eat()
  {
   food = null;
  }
  
  public void recycle()
  {
   dirtyDishes.enqueue(dish);
  }
 }
 
 private Queue<Dish> dirtyDishes = new BlockingQueue<Dish>();
 private Queue<Dish> cleanDishes = new BlockingQueue<Dish>();
 
 private final int NUM_DISHES_BOUGHT = 50;

 Restaurant()
 {
  for(int i=0; i<NUM_DISHES_BOUGHT; i++)
   cleanDishes.enqueue(new Dish());
  new DishWasher.start(); // 雇的一个洗碗工
 }
 
 public Meal serve(String kindOfFood, double amount)
 {
  Dish dish = cleanDishes.dequeue();
  Meal meal = new Meal(dish, new Food(kindOfFood, amount));
  return meal;
 }
 
 private class DishWasher extends Thread
 {
  public void run()
  {
   Dish dish = dirtyDishes.dequeue();
   dish.wash();
   cleanDishes.enqueue();
  }
 }
}

public Customer
{
 private void dine()
 {
  String kindOfFood = wantingFood();
  double amount = nowAppetite();
  Restaurant restaurant = selectOneRestaurant();
  Meal meal = restaurant.serve(kindOfFood, amount);
  meal.eat();
  meal.recycle();
 }
 
 public void main(String[] args)
 {
  new Customer().dine();
 }
}

2. 后来,餐馆规模有所扩张,一个洗碗工忙不过来,就又雇了两个,同时又多买了原来2倍的盘子,于是变成这样:

 private final int NUM_DISHES_BOUGHT = 150;

 Restaurant()
 {
  for(int i=0; i<NUM_DISHES_BOUGHT; i++)
   cleanDishes.enqueue(new Dish());
  new DishWasher.start(); // 雇的一个洗碗工
  new DishWasher.start(); // 新雇的洗完工
  new DishWasher.start(); // 新雇的洗完工
 }

3. 经过不断努力,餐馆生意突飞猛进,为了满足需要又买了更多盘子,多雇了更多的洗碗工. 但是这个时候,老板发现,这个方法不像以前那么有效了,因为餐馆的空间有限(只有一个JVM),多出来的盘子堆得很挤(内存紧张),同时洗碗工越多,他们之间就越显得碍手碍脚的(线程太多了互相竞争CPU时间). 老板为此几度扩建餐馆(买更好的服务器), 但是到了最后实在无法再扩建了-- 周围的地皮很变得贵,邻居也都开出天价的拆迁费(CPU已经装了16个,内存也已经没法再大了). 再多买盘子,多雇洗碗工,餐馆的业绩反而下降了(超出服务器负载容量,导致了系统颠簸).

4. 于是老板又想到开一家专门洗碗的分支机构(添加独立的洗碗专用服务器), 但是老板对管理分支机构和协调这样的业务往来并没有什么经验,他又是个很谨慎的企业家,所以开始了解相关的信息和技术. 经过调查研究,他发现以下这些情况:
 a. 有一些大小和布局合适的厂房正在出售或者出租(服务器+基本操作系统).
 b. 还有一些房产商提供进一步的解决方案,包括给厂房安装工业洗碗机和捆绑销售有一定防震性能,防止盘子被颠碎的卡车(系统集成商).
 c. 还有一些专业提供洗碗服务的公司(服务提供商),但是你必须自己把脏盘子送过去,再把干净盘子领回来,他们规定送盘子和取盘子的地点(API).
各家都有一定的销售业绩和客户群. 不过经过对他们客户的观察和总结发现:
 a. 他们的用户基本都是一些老手, 他们自己都非常精于厂房和里面设备的管理. 餐馆老板知道自己并不像他们那样深刻掌握了这方面的路子,如果采用这个方法学习成本和风险都很大.
 b. 他们的用户在这个特定方面的需求规模一般都比较小, 比较平常和容易管理; 有几家规模大的企业使用他们的服务过程中发现漏洞百出,被搞得焦头烂额.
 c. 好像大部分大规模的用户都选择了这样的服务,不过他们也不得不自己聘请了一些专业人员来和这些公司联络,处理日常事务. 这些专业人员有时候会跳槽,留下一些棘手的问题.

5. 正当老板为仅有的几个选择举棋不定的时候,从一个偶然的机会,他听说现在有一家叫做 众能(Capabilities) 的集团公司, 旗下有一家 洗刷家(Washers) 子公司, 他们宣称提供这样的服务:
 他们会给你一套标志物, 其中一个是脏盘子地点标志,另一个是干净盘子地点标志, 你只要把它们分别放在你想扔脏盘子的地方和想取干净盘子的地方就行了, 他们会处理其他的问题, 同时餐馆也不用再自己买盘子, 洗碗速度非常之快, 吞吐量足以满足这样规模餐馆的需要, 取用的时候可以保证总是能马上得到干净盘子.

 于是老板决定一试,同时也学会和开始使用起支持角色的程序设计语言,最后变成这样:

 public class Dish implements Washable
 {
  private boolean dirty=false;

  public boolean isDirty()
  {
   return dirty;
  }
  
  // 由 role (...) 修饰的类成员,只能由列表中的角色或者本身类来访问.
  role (Kitchener) void use()
  {
   dirty = true;
  }
  
  role (WasherPartner) void wash()
  {
   dirty = false;
  }
 }

 public role Kitchener
 {
 }

 public class Restaurant employs WasherPartner<Dish>
 {
  role (WasherPartner<Dish>) implements
  Dish getCleanDish() as getClean();
  
  role (WasherPartner<Dish>) implements
  void putDirtyDish(Dish dish) as putDirty(dish);
  
  public class Meal as Kitchener
  {
   private Dish dish;
   private Food food;
   
   Meal(Dish dish, Food food)
   {
    this.dish = dish;
    dish.use(); // 必须是 Kitchener 角色才能调用这个方法.
    this.food = food;
   }
   
   public void eat()
   {
    food = null;
   }
   
   public void recycle()
   {
    putDirtyDish(dish);
   }
  }
  
  Restaurant()
  {
  }
  
  public Meal serve(String kindOfFood, double amount)
  {
   Dish dish = getCleanDish();
   Meal meal = new Meal(dish, new Food(kindOfFood, amount));
   return meal;
  }
 }

之所以能够这样写是因为众能集团为洗刷业制定了如下标准:

 public interface Washable
 {
  role (WasherPartner) void wash();
 }
 
 public role WasherPartner<T implements Washable>
 {
  implements T getClean();
  implements void putDirty(T o);
 }
 
这看起来有点像C++的多继承,但是差别在于: role WasherPartner 是一个接口而不是具体的类, 这样 洗刷家(Washers) 公司就有绝对的自由来决定如何实现洗刷的细节,可以针对不同的情况提供完全不同的实现方式.

6. 老板非常高兴,因为这样修改以后对他的顾客来说没有丝毫的变化,消费习惯完全得以保留; 同时洗刷家(Washers)公司凭借雄厚的技术实力一直服务得的非常稳定可靠,在接下来又出现的几次餐馆营业规模急速攀升的冲击下依然没有造成效率瓶颈,洗刷家(Washers)公司本身场地的扩建和设备的扩充因为专业的管理也没有影响到餐馆的正常营业. 但是美中不足的是, 因为众能集团和洗刷家公司最开始时业务量很小,所以成本相对较高,收费也比较昂贵. 但是餐馆老板知道这个模式是唯一能够有效解决他眼前经营规模增长上的方式,不然只能限制企业的规模成长. 所以为了持续发展企业规模,他一直购买使用洗刷家公司的服务. 在后来的几年间,所有业务迅速增长的企业也逐渐发现这种模式的优势,给众能集团带来了快速增长的业务,集团的运行成本迅速降低,使得这种运作模式最终成为专业服务领域的主流模式,同时使用这种模式的企业也表现出前所未有的增长潜力,整个社会经济又向前迈进了一大步.


结论:

 当我们在无奈的容许AspectJ只涵盖编译范围的代码时, 当我们还在殚精竭虑的论证AOP到底应不应该访问目标类的私有成员时, 当我们还在因为编译产生的字节码会在自己不知情的情况下被改编而担心时, 当我们在为了搞清楚看到的一个public接口或者方法到底能不能调用而狂翻资料文档时, 当我们被相邻领域的名词和海量的资料折磨得狼狈不堪时, 当我们想方设法一遍一遍的给另一个同事解释自己接口中的几个方法必须遵循的调用顺序时, 当完全不知道一个方法会做什么事,却还不得不决定它是否需要事务支持时, 当因为没时间仔细阅读J2EE规范而屡犯错误时, 当不得不把java,SQL,JS,和HTML等等代码混为一谈时, 我们是不是能够获得一些动力, 来把各个方向,各种技术,各个团队,各个成员,他们的角色来理理清楚, 让它成为一种更直接,更准确,更简洁,更纯粹的语言表达方式?

程序设计语言--结构化,面向对象,接下来要怎么走?

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号