MVC纯C实现 [英] MVC implemented in pure C

查看:123
本文介绍了MVC纯C实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有谁知道,提供试图做模型视图控制器设计模式在C背景下直线前进的例子任何资源吗?尤其是嵌入式系统?

Does anybody know of any resources that provide a straight forward example of trying to do Model View Controller design pattern in a C context? And in particular an embedded system?

要澄清,我没有兴趣在C#,C ++,Objective-C中的Java,PHP或任何高级语言的例子。我想知道是什么人思考如何用纯ANSI C99,甚至C89接近这种设计模式。也许这甚至没有意义在C由于缺乏正规的OOP语言结构的?

To clarify, I am not interested in C#, C++, Objective-C, Java, PHP or any higher level language examples. I want to know what people think about how to approach this design pattern with pure ansi C99 or even C89. Maybe this doesn't even make sense in C because of the lack of formal OOP language constructs?

一些背景:我的同事和我都在搭载基于ARM的PSoC芯片的嵌入式系统的工作。我们有超过硬件设计和PCB控制,并有做软件开发,以提高我们产品的功能集。我们的模型将通常包括从模拟数据采集到在产品的数字转换器。的观点可能是一个网页,搭载嵌入式Web服务器,或者与电容式触摸控制的液晶显示屏。我们的控制器会或多或少是管理code这两个领域之间的关系的胶合逻辑。我们有很多不同的产品和变化的支持这么code重用是可取的。

Some context: my co-workers and I are working on embedded systems powered by Arm based PSoC chips. We have control over the hardware design and PCBs, and have to do software development to enhance our product's feature set. Our model would typically consist of data acquisition from Analog to Digital converters in the product. The views might be a web page powered by an embedded web server, or else an LCD screen with capacitive touch control. Our controllers would more or less be the glue logic that manages the relationship between these two areas of code. We have lots of different products and variations to support so code reuse is desirable.

不找非常详细的或企业级框架。而是简单的例子照亮好的策略分离编程的担忧,但朝向低级别C,如发现成语偏置结构,函数,事件驱动逻辑和一种抽象的消息传递的是有道理的温度。

Not looking for highly detailed or enterprise level frameworks. But rather simple examples that illuminate good strategies for separating the programming concerns, but with a bias toward the idioms found in lower level C, e.g. structs, functions, event driven logic and a kind of abstract message passing that makes sense in C.

由于我们需要使用C和有引导的很多东西我们自己的硬件的性质。在某些情况下,我们可以使用一个操作系统和在其他情况下,刚编译直到处理器并与主功能启动。一切都非常简陋,但寻找一个允许code重用,并希望加快软件工程过程的方法。

Because of the nature of the hardware we need to use C and have to bootstrap a lot of things ourselves. And in some cases we have access to an OS and in other cases just compile straight to processor and start with a main function. All very primitive, but looking for approaches that allow for code reuse and hopefully speed up the software engineering process.

推荐答案

Pshew ...这可能是一个漫长的答案......但在这里不用...

Pshew... this might be a long answer... but here goes...

首先,让我们开始与这句话:

First, let's start with this statement:

也许这甚至没有意义在C由于缺乏正规的OOP语言结构的?

无法反对更多的这种说法。当我将展示以后;只是因为C没有漂亮的关键字,如阶级并不意味着你不能做到同样的事情。

Couldn't disagree more with that statement. As I'll show later on; just because C doesn't have nifty keywords like "class" doesn't mean you can't accomplish the same things.

我会尽力通过这一步一步的去尽我所能 - 你的问题的流程如下。

I'll try to go through this step-by-step as best I can - following your question's flow.

我怀疑,根据你的问题的措辞,你有面向对象概念的pretty体面的把握(你甚至会想在图案方面,甚至有这些模式将如何发挥出来是个好主意为您的特定方案) ​​- 所以让我用C OOP做一个在30秒或更少教程。

I suspect, based on the phrasing of your question, that you have a pretty decent grasp of OOP concepts (you're even thinking in terms of patterns and even have a good idea of how those patterns will play out for your particular scenario) - so let me do an "OOP in C" tutorial in "30 seconds or less".

一旦你得到的东西,你会意识到挂起还有很多你可以比我要在这里展示做 - 但我只是想给你一个味道

Once you get the hang of things you'll realize there is a lot more you can do than what I'm going to show here - but I just want to give you a taste.

首先,我们有基本的阶级(跟我一起去研究这个)启动:

First, we'll start with a basic "class" (go with me on this):

foo.h中:

typedef struct Foo Foo;
Foo * FooCreate(int age, int something);
void FooSetAge(Foo * this, int age);
void FooFree(Foo * this);

Foo_Internal.h:(你会明白为什么我在第二个爆发了这一点)

#include "Foo.h"

struct Foo { 
     int age;
     int something;
};

void FooInitialize(Foo * this, int age, int something);

foo.c的:

#include "Foo_Internal.h"

// Constructor:
Foo * FooCreate(int age, int something) { 
    Foo * newFoo = malloc(sizeof(Foo));

    FooInitialize(newFoo);

    return newFoo;
}

void FooInitialize(Foo * this, int age, int something)
{
    this->age = age;
    this->something = something;
}

// "Property" setter:
void FooSetAge(Foo * this, int age) {
    this->age = age;
}

void FooFree(Foo * this) { 
    // Do any other freeing required here.
    free(this);
}

几件事情要注意:

Couple things to notice:


  • 我们躲在一个不透明的指针后面的实施细则。其他人不知道什么是在,因为这实现细节是在内部头文件,而不是公共头。

  • 我们实行实例方法就像一个OOP语言会 - 但我们必须手动传递this指针 - 其他语言只是为你做这个 - 但它不是一个大问题

  • 我们有属性。同样,其他语言将包属性的getter /在一个更好的语法设置 - 但所有这些都真正做幕后创造一些的getter / setter方法​​为你和翻译呼吁属性进入方法调用

  • We hid the implementation details of Foo behind an opaque pointer. Other people don't know what is in a Foo because that implementation detail is in the "internal" header file, not the "public" header.
  • We implement "instance methods" just like an OOP language would - except we have to manually pass the "this" pointer - other languages just do this for you - but it's not a big deal.
  • We have "properties". Again, other languages will wrap up property getters/settings in a nicer syntax - but all they are really doing behind the scenes is creating some getter/setter method for you and translating calls to the "properties" into method calls.

那么,如果我们想要一个的子类 - 这不仅增加了额外的功能 - 但可以取代一个?很简单:

So what if we want a "subclass" of Foo - which only adds additional functionality - but can be substituted for a Foo? Simple:

FooSubclass.h:

typedef struct FooSubclass FooSubclass;
FooSubclass * FooSubclassCreate(int age, int something, int somethingElse);
void FooSubclassSetSomethingElse(FooSubclass * this, int somethingElse);
void FooSubclassFree(FooSubclass * this);

FooSubclass_Internal.h:

#include "FooSubclass.h"
#include "Foo_Internal.h"

struct FooSubclass { 
     Foo base;
     int something;
};

void FooSubclassInitialize(FooSubclass * this, int age, int something, int somethingElse);

FooSubclass.c

#include "FooSubclass_Internal.h"

// Constructor:
Foo * FooSubclassCreate(int age, int something, int somethingElse) { 
    FooSubclass * newFooSubclass = malloc(sizeof(FooSubclass));

    FooSubclassInitialize(newFooSubclass, age, something, somethingElse);

    return newFooSubclass;
}

void FooSubclassInitialize(FooSubclass * this, int age, int something, int somethingElse) {
    FooInitialize(this, age, something);
    this->somethingElse = somethingElse;
} 

void FooSubclassSetSomethingElse(Foo * this, int somethingElse)
{
    this->somethingElse = somethingElse;
}

void FooSubclassFree(FooSubclass * this) { 
    // Do any other freeing required here.
    free(this);
}

现在,我要指出,就像我们造初始化,这实际上不叫的malloc ,但负责初始化成员变量 - 我们也确实需要deallocators - 这实际上不释放结构 - 而是自由/释放任何拥有的引用,等等。但是......我究竟要提到在部分下面的东西这或许可以解释为什么我没有费心这还没有。

Now, I should mention, just like we made "initializers" which don't actually call malloc, but are responsible for initializing the member variables - we also really need deallocators - which don't actually free the struct - but instead free/release any "owning" references, etc. However... I'm actually going to mention something in the section below which might explain why I didn't bother with that yet.

您现在应该看到 - 既然我们的 FooSubclass 的第一个成员,事实上,一个结构 - 任何参照 FooSubclass 也是一个有效的参照 - 这意味着它可以被用作这样pretty太多的任何地方。

You should notice now - that since our FooSubclass's first member is, in fact, a Foo struct - that any reference to a FooSubclass is also a valid reference to a Foo - meaning it can be used as such pretty much anywhere.

不过,也有一些小问题,与此 - ​​就像我在过去一段前面提到 - 这种技术实际上并没有让你的变更的基类的行为。 (这是我们希望为我们的取消分配实例做,例如)。

However, there are a few small issues with this - like I mentioned in the paragraph before last - this technique doesn't actually let you change behavior of the base class. (Something we'd like to do for deallocating our instance, for example).

让我们说我们有一些方法 - 我们会想出一个随机BS例子 - 一个名为计算

Let's say we have some method - we'll come up with a random BS example - called calculate.

我们希望呼吁计算返回一个值 - 但如果它被称为一个不同的值一个 FooSubclass

We want calling calculate on a Foo to return one value - but a different value if it was called on a FooSubclass.

这是在C简单 - 它实际上只是一个创建实际上通过调用函数指针引用的函数的封装方法的问题。 OOP语言为你做这个幕后,它通常是通过什么被称为虚函数表实施。

This is simple in C - it's really just a matter of creating a wrapper method which actually calls a function referenced by a function pointer. OOP languages do this for you behind the scenes and it's usually implemented via what's referred to as a VTable.

下面是一个例子(我将停止给完整的例子,转而关注相关部分):

Here's an example (I'm going to stop giving complete examples and instead focus on the relevant parts):

首先,我们定义该方法的签名。在这里,我们说calculateMethod是:一个指向它需要一个参数(指针),并返回一个int的方法。

First we define the signature of the method. Here we're saying "calculateMethod" is: a pointer to a method which takes one parameter (a pointer) and returns an int.

typedef int (*calculateMethod)(void *);

接下来,我们添加在我们的基类的成员变量,它指向的一些功能:

Next, we add a member variable in our base class which will point to some function:

struct Foo { 
    // ...
    calculateMethod calc;
    // ...
}

我们初始化这个用在 FooInitialize 法一些初始值(我们的基本实现):

We initialize this with some initial value in the FooInitialize method (for our base implementation):

int FooCalculate(Foo * this)
{
    this->calc(this);
}

int FooCalculateImplementation(void * this)
{
    Foo * thisFoo = (Foo *)this;
    return thisFoo->age + thisFoo->something;
}

void FooInitialize(Foo * this, ...)
{
    // ...
    this->calc = &FooCalculateImplementation;
    // ...
}

现在我们做一些方法供子类重写此方法 - 例如,例如,名为 Foo_Internal.h 文件中声明的方法无效FooSetCalculateMethod(富*此,calculateMethod值); - 瞧!方法可以在子类覆盖。

Now we make some way for subclasses to override this method - say, for example, a method declared in the Foo_Internal.h file called void FooSetCalculateMethod(Foo * this, calculateMethod value); - and voila! Methods which can be overridden in subclasses.

我们的模型通常包括从模拟数据采集于产品数字转换器。

确定 - 所以,型号可能是最容易实现的事 - 这是用来作为数据存储机制,简单的类。

OK - so, Model is probably the easiest thing to implement - simple "classes" which are used as data storage mechanisms.

您将不得不想办法的为您的特定方案(即嵌入式系统我不知道您的具体限制是什么 - 如果你担心RAM /持久的/ etc) - 但我想你不想让我潜入的反正。

You'll have to figure something out for your particular scenario (being an embedded system I'm not sure what your exact restrictions will be - and if you're worried about RAM / persistence / etc) - but I think you don't want me to dive into that anyways.

的意见可能是一个网页搭载嵌入式Web服务器,或者与电容式触摸控制的液晶显示屏。

有关物理的东西你一个控制面板上的查看可以是固定的按钮 - 或者,就像你说的,它可能是一个LCD或HTML。

For physical things your "view" may be fixed buttons on a control panel - or, like you said, it could be an LCD or HTML.

这里的底线是,你只需要它能够presenting系统的其余部分用于显示/视图改变事物一个简单的接口类 - 和封装IO的细节给用户。

The bottom line here is you simply need classes which are capable of presenting the rest of your system with a "simple" interface for displaying/changing things in the view - and encapsulate the details of IO to the user.

典型的IO的I部分需要在视图code中的至少一些小楔子。

Typically the "I" part of "IO" needs at least some small wedge of code in the view.

我不认为这是理想的 - 但是,大部分的时候,有不在身边有你的查看代理用户输入回你的控制器的好方法。也许你的系统有解决这个好办法 - 给你有完全的控制。

I don't think this is ideal - but, most of the time, there isn't a good way around having your "view" proxy user input back to your controllers. Maybe with your system there is a good way around this - given you have total control.

我希望你现在能看你怎么可以很容易地去创造一些是有关您需要的视图类。

I hope you can see now how you could easily go about creating some view classes which are relevant to your needs.

我们的控制器会或多或少是管理code这两个领域之间的关系胶合逻辑。

这通常是应用程序的核心。你可能需要多个控制器围绕在给定的时间 - 一个用于传感器数据的一个或多个任何UI你已经有了积极的,可能还有其他的入口/处理。

This is usually the guts of the application. You'll likely need more than one controller around at a given time - one for ingress/processing of sensor data, one or more for whatever UI you've got active, and possibly others.

不管怎么说,我希望帮助......我觉得我现在正在写一本书,所以我会停下来。

Anyways, I hope that helps... I feel like I'm writing a book now, so I'll stop.

让我知道如果你想要更多,或者帮助都没有。

Let me know if you want more, or if that helps at all.

这篇关于MVC纯C实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆